// Grant adds privileges to users. // Current status: // - Target: DATABASE X only // - Privileges: ALL, or one or more of READ, WRITE. // TODO(marc): open questions: // - should we have root always allowed and not present in the permissions list? // - should we make users case-insensitive? // Privileges: WRITE on database. // Notes: postgres requires the object owner. // mysql requires the "grant option" and the same privileges, and sometimes superuser. func (p *planner) Grant(n *parser.Grant) (planNode, error) { descriptor, err := p.getDescriptorFromTargetList(n.Targets) if err != nil { return nil, err } if !descriptor.HasPrivilege(p.user, parser.PrivilegeWrite) { return nil, fmt.Errorf("user %s does not have %s privilege on %s %s", p.user, parser.PrivilegeWrite, descriptor.TypeName(), descriptor.GetName()) } if err := descriptor.Grant(n); err != nil { return nil, err } // Now update the descriptor. // TODO(marc): do this inside a transaction. This will be needed // when modifying multiple descriptors in the same op. descKey := structured.MakeDescMetadataKey(descriptor.GetID()) if err := p.txn.Put(descKey, descriptor); err != nil { return nil, err } return &valuesNode{}, nil }
// writeDescriptor takes a Table or Database descriptor and writes it // if needed, incrementing the descriptor counter. func (p *planner) writeDescriptor(plainKey descriptorKey, descriptor descriptorProto, ifNotExists bool) error { key := plainKey.Key() // Check whether key exists. gr, err := p.txn.Get(key) if err != nil { return err } if gr.Exists() { if ifNotExists { // Noop. return nil } // Key exists, but we don't want it to: error out. return fmt.Errorf("%s %q already exists", descriptor.TypeName(), plainKey.Name()) } // Increment unique descriptor counter. if ir, err := p.txn.Inc(keys.DescIDGenerator, 1); err == nil { descriptor.SetID(structured.ID(ir.ValueInt() - 1)) } else { return err } // TODO(pmattis): The error currently returned below is likely going to be // difficult to interpret. // TODO(pmattis): Need to handle if-not-exists here as well. descKey := structured.MakeDescMetadataKey(descriptor.GetID()) b := client.Batch{} b.CPut(key, descKey, nil) b.CPut(descKey, descriptor, nil) return p.txn.Run(&b) }
func TestGrantDatabase(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) // The first `MaxReservedDescID` (plus 0) are set aside. expectedCounter := structured.MaxReservedDescID + 1 if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } descKey := structured.MakeDescMetadataKey(expectedCounter) desc := structured.DatabaseDescriptor{} if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 1 || desc.Read[0] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 1 || desc.Write[0] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Grant WRITE permissions. if _, err := sqlDB.Exec(`GRANT WRITE ON DATABASE TEST TO foo`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 1 || desc.Read[0] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 2 || desc.Write[0] != "foo" || desc.Write[1] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Grant ALL Permissions. if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO bar`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 2 || desc.Read[0] != "bar" || desc.Read[1] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 3 || desc.Write[0] != "bar" || desc.Write[1] != "foo" || desc.Write[2] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Adding permissions to root is a noop. if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO root`); err != nil { t.Fatal(err) } }
func TestKeyAddress(t *testing.T) { defer leaktest.AfterTest(t) testCases := []struct { key, expAddress proto.Key }{ {structured.MakeNameMetadataKey(0, "foo"), proto.Key("\x00name-\bfoo")}, {structured.MakeNameMetadataKey(0, "BAR"), proto.Key("\x00name-\bbar")}, {structured.MakeDescMetadataKey(123), proto.Key("\x00desc-\t{")}, } for i, test := range testCases { result := keys.KeyAddress(test.key) if !result.Equal(test.expAddress) { t.Errorf("%d: expected address for key %q doesn't match %q", i, test.key, test.expAddress) } } }
// RenameDatabase alters a databsase name // Privileges: "root" user. // Notes: postgres requires superuser, db owner, or "CREATEDB". // mysql >= 5.1.23 does not allow database renames func (p *planner) RenameDatabase(n *parser.RenameDatabase) (planNode, error) { if n.Name == "" || n.NewName == "" { return nil, errEmptyDatabaseName } if n.Name == n.NewName { //noop return &valuesNode{}, nil } if p.user != security.RootUser { return nil, fmt.Errorf("only %s is allowed to rename databases", security.RootUser) } dbDesc, err := p.getDatabaseDesc(string(n.Name)) if err != nil { return nil, err } // Now update the nameMetadataKey and the descriptor. descKey := structured.MakeDescMetadataKey(dbDesc.GetID()) dbDesc.SetName(string(n.NewName)) b := client.Batch{} b.CPut(databaseKey{string(n.NewName)}.Key(), descKey, nil) b.Put(descKey, dbDesc) b.Del(databaseKey{string(n.Name)}.Key()) if err := p.txn.Run(&b); err != nil { if _, ok := err.(*proto.ConditionFailedError); ok { return nil, fmt.Errorf("the new database name %s already exists", string(n.NewName)) } return nil, err } return &valuesNode{}, nil }
func TestDatabaseDescriptor(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) // The first `MaxReservedDescID` (plus 0) are set aside. expectedCounter := int64(structured.MaxReservedDescID + 1) // Test values before creating the database. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. nameKey := structured.MakeNameMetadataKey(structured.RootNamespaceID, "test") if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatal("expected non-existing key") } // Write some junk that is going to interfere with table creation. dbDescKey := structured.MakeDescMetadataKey(structured.ID(expectedCounter)) if err := kvDB.CPut(dbDescKey, "foo", nil); err != nil { t.Fatal(err) } // Table creation should fail, and nothing should have been written. if _, err := sqlDB.Exec(`CREATE DATABASE test`); !testutils.IsError(err, "unexpected value") { t.Fatalf("unexpected error %s", err) } if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } if kvs, err := kvDB.Scan(keys.NameMetadataPrefix, keys.NameMetadataPrefix.PrefixEnd(), 0); err != nil { t.Fatal(err) } else { if a, e := len(kvs), 0; a != e { t.Fatalf("expected %d keys to have been written, found %d keys", e, a) } } // Remove the junk; allow table creation to proceed. if err := kvDB.Del(dbDescKey); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } expectedCounter++ // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(dbDescKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // Now try to create it again. We should fail, but not increment the counter. if _, err := sqlDB.Exec(`CREATE DATABASE test`); err == nil { t.Fatal("failure expected") } // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(dbDescKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } }
func TestDatabaseDescriptor(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) // The first `MaxReservedDescID` (plus 0) are set aside. expectedCounter := int64(structured.MaxReservedDescID + 1) // Test values before creating the database. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if ir.ValueInt() != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt()) } // Database name. nameKey := structured.MakeNameMetadataKey(structured.RootNamespaceID, "test") if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatal("expected non-existing key") } if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } expectedCounter++ // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if ir.ValueInt() != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt()) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. descKey := structured.MakeDescMetadataKey(structured.ID(expectedCounter - 1)) if gr, err := kvDB.Get(descKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // Now try to create it again. We should fail, but not increment the counter. if _, err := sqlDB.Exec(`CREATE DATABASE test`); err == nil { t.Fatal("failure expected") } // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if ir.ValueInt() != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, ir.ValueInt()) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(descKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } }
func TestRevoke(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) // The first `MaxReservedDescID` (plus 0) are set aside. expectedCounter := structured.MaxReservedDescID + 1 if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } descKey := structured.MakeDescMetadataKey(expectedCounter) desc := structured.DatabaseDescriptor{} if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 1 || desc.Read[0] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 1 || desc.Write[0] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Add some permissions. if _, err := sqlDB.Exec(`GRANT ALL ON DATABASE TEST TO rw`); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`GRANT READ ON DATABASE TEST TO reader`); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`GRANT WRITE ON DATABASE TEST TO writer`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 3 || len(desc.Write) != 3 { t.Fatalf("wrong read/write length: %d, %d", len(desc.Read), len(desc.Write)) } // Test some revokes. if _, err := sqlDB.Exec(`REVOKE WRITE ON DATABASE TEST FROM writer,reader`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 3 { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 2 || desc.Write[0] != security.RootUser || desc.Write[1] != "rw" { t.Fatalf("wrong Write list: %+v", desc.Write) } // Remove ALL Permissions. if _, err := sqlDB.Exec(`REVOKE ALL ON DATABASE TEST FROM rw`); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } if len(desc.Read) != 2 || desc.Read[0] != "reader" || desc.Read[1] != security.RootUser { t.Fatalf("wrong Read list: %+v", desc.Read) } if len(desc.Write) != 1 || desc.Write[0] != security.RootUser { t.Fatalf("wrong Write list: %+v", desc.Write) } // Removing permissions for "root" fails. if _, err := sqlDB.Exec(`REVOKE READ ON DATABASE TEST FROM root`); err == nil { t.Fatal("unexpected success") } }