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

sql: populate pg_catalog.pg_default_acl table #67872

Merged
merged 1 commit into from
Jul 23, 2021
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
104 changes: 104 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/pg_catalog_pg_default_acl
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
statement ok
ALTER DEFAULT PRIVILEGES GRANT SELECT ON TABLES TO PUBLIC;
ALTER DEFAULT PRIVILEGES GRANT USAGE ON TYPES TO PUBLIC;
ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO PUBLIC;
ALTER DEFAULT PRIVILEGES GRANT SELECT ON SEQUENCES TO PUBLIC;

# Public should appear as an empty string with privileges.
query OOOTT colnames,rowsort
SELECT * FROM PG_CATALOG.PG_DEFAULT_ACL
----
oid defaclrole defaclnamespace defaclobjtype defaclacl
4149409857 1546506610 0 T {=U/}
4149409857 1546506610 0 n {=U/}
4149409857 1546506610 0 r {=r/}
4149409857 1546506610 0 S {=r/}

statement ok
CREATE USER foo

statement ok
CREATE USER bar

statement ok
ALTER DEFAULT PRIVILEGES GRANT ALL ON TABLES TO foo, bar;
ALTER DEFAULT PRIVILEGES GRANT ALL ON TYPES TO foo, bar;
ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO foo, bar;
ALTER DEFAULT PRIVILEGES GRANT ALL ON SEQUENCES TO foo, bar;

query OOOTT colnames,rowsort
SELECT * FROM PG_CATALOG.PG_DEFAULT_ACL
----
oid defaclrole defaclnamespace defaclobjtype defaclacl
4149409857 1546506610 0 T {bar=U/,foo=U/,=U/}
4149409857 1546506610 0 n {bar=CU/,foo=CU/,=U/}
4149409857 1546506610 0 r {bar=Cadrw/,foo=Cadrw/,=r/}
4149409857 1546506610 0 S {bar=Cadrw/,foo=Cadrw/,=r/}

statement ok
GRANT foo, bar TO root;

statement ok
ALTER DEFAULT PRIVILEGES FOR ROLE foo, bar GRANT ALL ON TABLES TO foo, bar;
ALTER DEFAULT PRIVILEGES FOR ROLE foo, bar GRANT ALL ON TYPES TO foo, bar;
ALTER DEFAULT PRIVILEGES FOR ROLE foo, bar GRANT ALL ON SCHEMAS TO foo, bar;
ALTER DEFAULT PRIVILEGES FOR ROLE foo, bar GRANT ALL ON SEQUENCES TO foo, bar;

# 12 rows should exist, 4 for each role, root, foo and bar.
query OOOTT colnames,rowsort
SELECT * FROM PG_CATALOG.PG_DEFAULT_ACL
----
oid defaclrole defaclnamespace defaclobjtype defaclacl
542080048 1791217281 0 n {bar=CU/,foo=CU/}
542080048 1791217281 0 r {bar=Cadrw/,foo=Cadrw/}
542080048 1791217281 0 S {bar=Cadrw/,foo=Cadrw/}
542080048 1791217281 0 T {bar=U/,foo=U/}
38059971 2026795574 0 r {bar=Cadrw/,foo=Cadrw/}
38059971 2026795574 0 S {bar=Cadrw/,foo=Cadrw/}
38059971 2026795574 0 T {bar=U/,foo=U/}
38059971 2026795574 0 n {bar=CU/,foo=CU/}
4149409857 1546506610 0 n {bar=CU/,foo=CU/,=U/}
4149409857 1546506610 0 r {bar=Cadrw/,foo=Cadrw/,=r/}
4149409857 1546506610 0 S {bar=Cadrw/,foo=Cadrw/,=r/}
4149409857 1546506610 0 T {bar=U/,foo=U/,=U/}

statement ok
ALTER DEFAULT PRIVILEGES FOR ROLE foo, bar REVOKE ALL ON TABLES FROM foo, bar;
ALTER DEFAULT PRIVILEGES FOR ROLE foo, bar REVOKE ALL ON TYPES FROM foo, bar;
ALTER DEFAULT PRIVILEGES FOR ROLE foo, bar REVOKE ALL ON SCHEMAS FROM foo, bar;
ALTER DEFAULT PRIVILEGES FOR ROLE foo, bar REVOKE ALL ON SEQUENCES FROM foo, bar;

# Revoking all should remove 8 rows, 4 for each foo and bar.
query OOOTT colnames,rowsort
SELECT * FROM PG_CATALOG.PG_DEFAULT_ACL
----
oid defaclrole defaclnamespace defaclobjtype defaclacl
4149409857 1546506610 0 T {bar=U/,foo=U/,=U/}
4149409857 1546506610 0 n {bar=CU/,foo=CU/,=U/}
4149409857 1546506610 0 r {bar=Cadrw/,foo=Cadrw/,=r/}
4149409857 1546506610 0 S {bar=Cadrw/,foo=Cadrw/,=r/}

statement ok
ALTER DEFAULT PRIVILEGES REVOKE SELECT ON TABLES FROM foo, bar, public;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON TYPES FROM foo, bar, public;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM foo, bar, public;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON SEQUENCES FROM foo, bar, public;

# Revoke ALL from types, schemas, sequences and select from tables.
# Only one entry should be left, for tables and 'r' should not be present.
query OOOTT colnames,rowsort
SELECT * FROM PG_CATALOG.PG_DEFAULT_ACL
----
oid defaclrole defaclnamespace defaclobjtype defaclacl
4149409857 1546506610 0 r {bar=Cadw/,foo=Cadw/}

# GRANT, DROP and ZONECONFIG should not show up in defaclacl.
statement ok
ALTER DEFAULT PRIVILEGES REVOKE ALL ON TABLES FROM foo, bar, public;
ALTER DEFAULT PRIVILEGES GRANT GRANT, DROP, ZONECONFIG ON TABLES TO foo;

query OOOTT colnames,rowsort
SELECT * FROM PG_CATALOG.PG_DEFAULT_ACL
----
oid defaclrole defaclnamespace defaclobjtype defaclacl
4149409857 1546506610 0 r {foo=/}
91 changes: 90 additions & 1 deletion pkg/sql/pg_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/parser"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
"github.com/cockroachdb/cockroach/pkg/sql/privilege"
"github.com/cockroachdb/cockroach/pkg/sql/sem/builtins"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqlerrors"
Expand Down Expand Up @@ -1107,9 +1108,84 @@ var pgCatalogDefaultACLTable = virtualSchemaTable{
https://www.postgresql.org/docs/9.6/catalog-pg-default-acl.html`,
schema: vtable.PGCatalogDefaultACL,
populate: func(ctx context.Context, p *planner, dbContext catalog.DatabaseDescriptor, addRow func(...tree.Datum) error) error {
h := makeOidHasher()
if dbContext.GetDefaultPrivileges() == nil {
return nil
}
for _, defaultPrivs := range dbContext.GetDefaultPrivileges().DefaultPrivileges {
// Need to consider the case of USAGE for Public as well.
for objectType, privs := range defaultPrivs.DefaultPrivilegesPerObject {
// Type of object this entry is for:
// r = relation (table, view), S = sequence, f = function, T = type, n = schema.
var c string
switch objectType {
case tree.Tables:
c = "r"
case tree.Sequences:
c = "S"
case tree.Types:
c = "T"
case tree.Schemas:
c = "n"
}
privilegeObjectType := targetObjectToPrivilegeObject[objectType]
arr := tree.NewDArray(types.String)
for _, userPrivs := range privs.Users {
var user string
if userPrivs.UserProto.Decode().IsPublicRole() {
// Postgres represents Public in defacl as an empty string.
user = ""
} else {
user = userPrivs.UserProto.Decode().Normalized()
}

privileges := privilege.ListFromBitField(
userPrivs.Privileges, privilegeObjectType,
)
defaclItem := fmt.Sprintf(`%s=%s/%s`,
user,
privileges.ListToACL(
privilegeObjectType,
),
// TODO(richardjcai): CockroachDB currently does not track grantors
// See: https://github.com/cockroachdb/cockroach/issues/67442.
"", /* grantor */
)

if len(defaclItem) != 0 {
if err := arr.Append(
tree.NewDString(defaclItem)); err != nil {
return err
}
}
}

if len(arr.Array) == 0 {
continue
}

// TODO(richardjcai): Update this logic once default privileges on
// schemas are supported.
// See: https://github.com/cockroachdb/cockroach/issues/67376.
schemaName := ""
rowOid := h.DBSchemaRoleOid(
dbContext.GetID(),
schemaName,
defaultPrivs.UserProto.Decode().Normalized(),
)
if err := addRow(
rowOid, // row identifier oid
h.UserOid(defaultPrivs.UserProto.Decode()), // defaclrole oid
oidZero, // defaclnamespace oid
tree.NewDString(c), // defaclobjtype char
arr, // defaclacl aclitem[]
); err != nil {
return err
}
}
}
return nil
},
unimplemented: true,
}

var (
Expand Down Expand Up @@ -3389,6 +3465,7 @@ const (
operatorTypeTag
enumEntryTypeTag
rewriteTypeTag
dbSchemaRoleTypeTag
)

func (h oidHasher) writeTypeTag(tag oidTypeTag) {
Expand Down Expand Up @@ -3559,6 +3636,18 @@ func (h oidHasher) rewriteOid(source descpb.ID, depended descpb.ID) *tree.DOid {
return h.getOid()
}

// DBSchemaRoleOid creates an OID based on the combination of a db/schema/role.
// This is used to generate a unique row identifier for pg_default_acl.
func (h oidHasher) DBSchemaRoleOid(
dbID descpb.ID, scName string, normalizedRole string,
) *tree.DOid {
h.writeTypeTag(dbSchemaRoleTypeTag)
h.writeDB(dbID)
h.writeSchema(scName)
RichardJCai marked this conversation as resolved.
Show resolved Hide resolved
h.writeStr(normalizedRole)
return h.getOid()
}

func tableOid(id descpb.ID) *tree.DOid {
return tree.NewDOid(tree.DInt(id))
}
Expand Down
35 changes: 34 additions & 1 deletion pkg/sql/privilege/privilege.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (pl List) Less(i, j int) bool {
}

// names returns a list of privilege names in the same
// order as 'pl'.
// order as "pl".
func (pl List) names() []string {
ret := make([]string, len(pl))
for i, p := range pl {
Expand Down Expand Up @@ -236,3 +236,36 @@ func GetValidPrivilegesForObject(objectType ObjectType) List {
panic(errors.AssertionFailedf("unknown object type %s", objectType))
}
}

// ListToACL converts a list of privileges to a list of Postgres
// ACL items.
// See: https://www.postgresql.org/docs/13/ddl-priv.html#PRIVILEGE-ABBREVS-TABLE
// for privileges and their ACL abbreviations.
func (pl List) ListToACL(objectType ObjectType) string {
privileges := pl
// If ALL is present, explode ALL into the underlying privileges.
if pl.Contains(ALL) {
privileges = GetValidPrivilegesForObject(objectType)
}
chars := make([]string, len(privileges))
for _, privilege := range privileges {
switch privilege {
case CREATE:
chars = append(chars, "C")
case SELECT:
chars = append(chars, "r")
case INSERT:
chars = append(chars, "a")
case DELETE:
chars = append(chars, "d")
case UPDATE:
chars = append(chars, "w")
case USAGE:
chars = append(chars, "U")
case CONNECT:
chars = append(chars, "c")
}
}
sort.Strings(chars)
return strings.Join(chars, "")
}