Make granting on ALL TABLES IN SCHEMA idempotent

Define a proper SELECT statement to feed into Postgresql_psql's
`unless` parameter that checks if there are any tables in the specified
schema for which the specified role *does not* have the specified
privilege. Only then allow the GRANT statement to be executed. For
details see comments.

Note that this, too, suffers from the problem that there is no feasible
way to check if a role has ALL PRIVILEGES on a table in plain SQL. By
terrible convention the INSERT privilege represents ALL PRIVILEGES here.
This commit is contained in:
Andreas Ntaflos 2015-02-18 00:47:40 +01:00
parent 4dbf624b2a
commit dbbb7aa2b3

View file

@ -75,10 +75,45 @@ define postgresql::server::grant (
$on_db = $db
}
'ALL TABLES IN SCHEMA': {
validate_string($_privilege, 'SELECT', 'INSERT', 'UPDATE', 'REFERENCES',
'ALL', 'ALL PRIVILEGES')
$unless_function = false # There is no way to test it simply
validate_string($_privilege,'SELECT','INSERT','UPDATE','DELETE',
'TRUNCATE','REFERENCES','TRIGGER','ALL','ALL PRIVILEGES')
$unless_function = 'custom'
$on_db = $db
$schema = $object_name
# Again there seems to be no easy way in plain SQL to check if ALL
# PRIVILEGES are granted on a table. By convention we use INSERT
# here to represent ALL PRIVILEGES (truly terrible).
$custom_privilege = $_privilege ? {
'ALL' => 'INSERT',
'ALL PRIVILEGES' => 'INSERT',
default => $_privilege,
}
# This checks if there is a difference between the tables in the
# specified schema and the tables for which the role has the specified
# privilege. It uses the EXCEPT clause which computes the set of rows
# that are in the result of the first SELECT statement but not in the
# result of the second one. It then counts the number of rows from this
# operation. If this number is zero then the role has the specified
# privilege for all tables in the schema and the whole query returns a
# single row, which satisfies the `unless` parameter of Postgresql_psql.
# If this number is not zero then there is at least one table for which
# the role does not have the specified privilege, making it necessary to
# execute the GRANT statement.
$custom_unless = "SELECT 1 FROM (
SELECT table_name
FROM information_schema.tables
WHERE table_schema='${schema}'
EXCEPT DISTINCT
SELECT table_name
FROM information_schema.role_table_grants
WHERE grantee='${role}'
AND table_schema='${schema}'
AND privilege_type='${custom_privilege}'
) P
HAVING count(P.table_name) = 0"
}
default: {
fail("Missing privilege validation for object type ${_object_type}")
@ -103,8 +138,9 @@ define postgresql::server::grant (
}
$_unless = $unless_function ? {
false => undef,
default => "SELECT 1 WHERE ${unless_function}('${role}',
false => undef,
'custom' => $custom_unless,
default => "SELECT 1 WHERE ${unless_function}('${role}',
'${_granted_object}', '${unless_privilege}')",
}