Fix postgresql_user to understand PG namespaces
Previously postgresql_user quoted user supplied identifers to create grant statements that look like this: GRANT SELECT on "tablename" to "user"; Which only works if the tablename is not in a namespace. If you supply a namespaced tabelname like "report.revenue" then it creates this incorrect statement: GRANT SELECT on "report.revenue" to "user"; Which will not find the "revenue" table in the "report" namespace, but will rather look for a table named "report.revenue" in the current (default public) namespace. The correct form is: GRANT SELECT on "report"."revenue" to "user"; This approach could have the unfortunate effect that code that previously relied on the other behavior to grant privileges on tables with periods in their names may now break. PostgreSQL users typically shouldn't name tables as such, and users can still access the old behavior and use tablenames with periods in the if they must by supplying their own quoting.
This commit is contained in:
parent
600f7bcdf0
commit
927a30c404
1 changed files with 21 additions and 2 deletions
|
@ -245,16 +245,35 @@ def get_table_privileges(cursor, user, table):
|
|||
return set([x[0] for x in cursor.fetchall()])
|
||||
|
||||
|
||||
def quote_pg_identifier(identifier):
|
||||
"""
|
||||
quote postgresql identifiers involving zero or more namespaces
|
||||
"""
|
||||
|
||||
if '"' in identifier:
|
||||
# the user has supplied their own quoting. we have to hope they're
|
||||
# doing it right. Maybe they have an unfortunately named table
|
||||
# containing a period in the name, such as: "public"."users.2013"
|
||||
return identifier
|
||||
|
||||
tokens = identifier.strip().split(".")
|
||||
quoted_tokens = []
|
||||
for token in tokens:
|
||||
quoted_tokens.append('"%s"' % (token, ))
|
||||
return ".".join(quoted_tokens)
|
||||
|
||||
def grant_table_privilege(cursor, user, table, priv):
|
||||
prev_priv = get_table_privileges(cursor, user, table)
|
||||
query = 'GRANT %s ON TABLE \"%s\" TO \"%s\"' % (priv, table, user)
|
||||
query = 'GRANT %s ON TABLE %s TO %s' % (
|
||||
priv, quote_pg_identifier(table), quote_pg_identifier(user), )
|
||||
cursor.execute(query)
|
||||
curr_priv = get_table_privileges(cursor, user, table)
|
||||
return len(curr_priv) > len(prev_priv)
|
||||
|
||||
def revoke_table_privilege(cursor, user, table, priv):
|
||||
prev_priv = get_table_privileges(cursor, user, table)
|
||||
query = 'REVOKE %s ON TABLE \"%s\" FROM \"%s\"' % (priv, table, user)
|
||||
query = 'REVOKE %s ON TABLE %s FROM %s' % (
|
||||
priv, quote_pg_identifier(table), quote_pg_identifier(user), )
|
||||
cursor.execute(query)
|
||||
curr_priv = get_table_privileges(cursor, user, table)
|
||||
return len(curr_priv) < len(prev_priv)
|
||||
|
|
Loading…
Reference in a new issue