Skip to content

Commit baa21d5

Browse files
author
George Hansper
committed
postgresql::server::grant with ensure => absent uses REVOKE instead of GRANT
1 parent db9b347 commit baa21d5

File tree

6 files changed

+408
-81
lines changed

6 files changed

+408
-81
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,16 @@ Default value: 'template0'.
11391139

11401140
Manages grant-based access privileges for users, wrapping the `postgresql::server::database_grant` for database specific permissions. Consult the [PostgreSQL documentation for `grant`](http://www.postgresql.org/docs/current/static/sql-grant.html) for more information.
11411141

1142+
##### `ensure`
1143+
1144+
Specifies whether to grant or revoke the privilege. Default is to grant the privilege.
1145+
1146+
Valid values: 'present', 'absent'.
1147+
* 'present' to grant the privilege
1148+
* 'absent' to revoke the privilege
1149+
1150+
Default value: 'present'.
1151+
11421152
#### `connect_settings`
11431153

11441154
Specifies a hash of environment variables used when connecting to a remote server.
@@ -1205,6 +1215,16 @@ By default, the package specified with `package_name` is installed when the exte
12051215

12061216
Manages grant-based access privileges for roles. See [PostgreSQL documentation for `grant`](http://www.postgresql.org/docs/current/static/sql-grant.html) for more information.
12071217

1218+
##### `ensure`
1219+
1220+
Specifies whether to grant or revoke the privilege. Default is to grant the privilege.
1221+
1222+
Valid values: 'present', 'absent'.
1223+
* 'present' to grant the privilege
1224+
* 'absent' to revoke the privilege
1225+
1226+
Default value: 'present'.
1227+
12081228
##### `db`
12091229

12101230
Specifies the database to which you are granting access.
@@ -1553,6 +1573,16 @@ Default value: the namevar.
15531573

15541574
Manages grant-based access privileges for users. Consult the PostgreSQL documentation for `grant` for more information.
15551575

1576+
##### `ensure`
1577+
1578+
Specifies whether to grant or revoke the privilege. Default is to grant the privilege.
1579+
1580+
Valid values: 'present', 'absent'.
1581+
* 'present' to grant the privilege
1582+
* 'absent' to revoke the privilege
1583+
1584+
Default value: 'present'.
1585+
15561586
##### `connect_settings`
15571587

15581588
Specifies a hash of environment variables used when connecting to a remote server.

manifests/server/database_grant.pp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
$privilege,
44
$db,
55
$role,
6+
$ensure = undef,
67
$psql_db = undef,
78
$psql_user = undef,
89
$connect_settings = undef,
910
) {
1011
postgresql::server::grant { "database:${name}":
12+
ensure => $ensure,
1113
role => $role,
1214
db => $db,
1315
privilege => $privilege,

manifests/server/grant.pp

Lines changed: 148 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,22 @@
2727
Integer $port = $postgresql::server::port,
2828
Boolean $onlyif_exists = false,
2929
Hash $connect_settings = $postgresql::server::default_connect_settings,
30+
Enum['present',
31+
'absent'] $ensure = 'present',
3032
) {
3133

34+
case $ensure {
35+
default: {
36+
# default is 'present'
37+
$sql_command = 'GRANT %s ON %s "%s" TO "%s"'
38+
$unless_is = true
39+
}
40+
'absent': {
41+
$sql_command = 'REVOKE %s ON %s "%s" FROM "%s"'
42+
$unless_is = false
43+
}
44+
}
45+
3246
$group = $postgresql::server::group
3347
$psql_path = $postgresql::server::psql_path
3448

@@ -81,7 +95,10 @@
8195
}
8296
$unless_function = 'has_database_privilege'
8397
$on_db = $psql_db
84-
$onlyif_function = undef
98+
$onlyif_function = $ensure ? {
99+
default => undef,
100+
'absent' => 'role_exists',
101+
}
85102
}
86103
'SCHEMA': {
87104
$unless_privilege = $_privilege ? {
@@ -149,43 +166,78 @@
149166
# If this number is not zero then there is at least one sequence for which
150167
# the role does not have the specified privilege, making it necessary to
151168
# execute the GRANT statement.
152-
$custom_unless = "SELECT 1 FROM (
153-
SELECT sequence_name
154-
FROM information_schema.sequences
155-
WHERE sequence_schema='${schema}'
156-
EXCEPT DISTINCT
157-
SELECT object_name as sequence_name
158-
FROM (
159-
SELECT object_schema,
160-
object_name,
161-
grantee,
162-
CASE privs_split
163-
WHEN 'r' THEN 'SELECT'
164-
WHEN 'w' THEN 'UPDATE'
165-
WHEN 'U' THEN 'USAGE'
166-
END AS privilege_type
167-
FROM (
168-
SELECT DISTINCT
169-
object_schema,
170-
object_name,
171-
(regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee,
172-
regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split
173-
FROM (
174-
SELECT n.nspname as object_schema,
175-
c.relname as object_name,
176-
regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs
177-
FROM pg_catalog.pg_class c
178-
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
179-
WHERE c.relkind = 'S'
180-
AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' )
181-
) P1
182-
) P2
183-
) P3
184-
WHERE grantee='${role}'
185-
AND object_schema='${schema}'
186-
AND privilege_type='${custom_privilege}'
187-
) P
188-
HAVING count(P.sequence_name) = 0"
169+
if $ensure == 'present' {
170+
$custom_unless = "SELECT 1 WHERE NOT EXISTS (
171+
SELECT sequence_name
172+
FROM information_schema.sequences
173+
WHERE sequence_schema='${schema}'
174+
EXCEPT DISTINCT
175+
SELECT object_name as sequence_name
176+
FROM (
177+
SELECT object_schema,
178+
object_name,
179+
grantee,
180+
CASE privs_split
181+
WHEN 'r' THEN 'SELECT'
182+
WHEN 'w' THEN 'UPDATE'
183+
WHEN 'U' THEN 'USAGE'
184+
END AS privilege_type
185+
FROM (
186+
SELECT DISTINCT
187+
object_schema,
188+
object_name,
189+
(regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee,
190+
regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split
191+
FROM (
192+
SELECT n.nspname as object_schema,
193+
c.relname as object_name,
194+
regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs
195+
FROM pg_catalog.pg_class c
196+
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
197+
WHERE c.relkind = 'S'
198+
AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' )
199+
) P1
200+
) P2
201+
) P3
202+
WHERE grantee='${role}'
203+
AND object_schema='${schema}'
204+
AND privilege_type='${custom_privilege}'
205+
)"
206+
} else {
207+
# ensure == absent
208+
$custom_unless = "SELECT 1 WHERE NOT EXISTS (
209+
SELECT object_name as sequence_name
210+
FROM (
211+
SELECT object_schema,
212+
object_name,
213+
grantee,
214+
CASE privs_split
215+
WHEN 'r' THEN 'SELECT'
216+
WHEN 'w' THEN 'UPDATE'
217+
WHEN 'U' THEN 'USAGE'
218+
END AS privilege_type
219+
FROM (
220+
SELECT DISTINCT
221+
object_schema,
222+
object_name,
223+
(regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee,
224+
regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split
225+
FROM (
226+
SELECT n.nspname as object_schema,
227+
c.relname as object_name,
228+
regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs
229+
FROM pg_catalog.pg_class c
230+
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
231+
WHERE c.relkind = 'S'
232+
AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' )
233+
) P1
234+
) P2
235+
) P3
236+
WHERE grantee='${role}'
237+
AND object_schema='${schema}'
238+
AND privilege_type='${custom_privilege}'
239+
)"
240+
}
189241
}
190242
'TABLE': {
191243
$unless_privilege = $_privilege ? {
@@ -233,37 +285,62 @@
233285
$schema = $object_name
234286

235287
# Again there seems to be no easy way in plain SQL to check if ALL
236-
# PRIVILEGES are granted on a table. By convention we use INSERT
237-
# here to represent ALL PRIVILEGES (truly terrible).
238-
$custom_privilege = $_privilege ? {
239-
'ALL' => 'INSERT',
240-
'ALL PRIVILEGES' => 'INSERT',
241-
default => $_privilege,
288+
# PRIVILEGES are granted on a table.
289+
# There are currently 7 possible priviliges:
290+
# ('SELECT','UPDATE','INSERT','DELETE','TRIGGER','REFERENCES','TRUNCATE')
291+
# This list is consistant from Postgresql 8.0
292+
#
293+
# There are 4 cases to cover, each with it's own distinct unless clause:
294+
# grant ALL
295+
# grant SELECT (or INSERT or DELETE ...)
296+
# revoke ALL
297+
# revoke SELECT (or INSERT or DELETE ...)
298+
299+
if $ensure == 'present' {
300+
if $_privilege == 'ALL' or $_privilege == 'ALL PRIVILEGES' {
301+
# GRANT ALL
302+
$custom_unless = "SELECT 1 WHERE NOT EXISTS
303+
( SELECT 1 FROM pg_catalog.pg_tables AS t,
304+
(VALUES ('SELECT'), ('UPDATE'), ('INSERT'), ('DELETE'), ('TRIGGER'), ('REFERENCES'), ('TRUNCATE')) AS p(privilege_type)
305+
WHERE t.schemaname = '${schema}'
306+
AND NOT EXISTS (
307+
SELECT 1 FROM information_schema.role_table_grants AS g
308+
WHERE g.grantee = '${role}'
309+
AND g.table_schema = '${schema}'
310+
AND g.privilege_type = p.privilege_type
311+
)
312+
)"
313+
314+
} else {
315+
# GRANT $_privilege
316+
$custom_unless = "SELECT 1 WHERE NOT EXISTS
317+
( SELECT 1 FROM pg_catalog.pg_tables AS t
318+
WHERE t.schemaname = '${schema}'
319+
AND NOT EXISTS (
320+
SELECT 1 FROM information_schema.role_table_grants AS g
321+
WHERE g.grantee = '${role}'
322+
AND g.table_schema = '${schema}'
323+
AND g.privilege_type = '${_privilege}'
324+
)
325+
)"
326+
}
327+
} else {
328+
if $_privilege == 'ALL' or $_privilege == 'ALL PRIVILEGES' {
329+
# REVOKE ALL
330+
$custom_unless = "SELECT 1 WHERE NOT EXISTS
331+
( SELECT table_name FROM information_schema.role_table_grants
332+
WHERE grantee = '${role}' AND table_schema ='${schema}'
333+
)"
334+
} else {
335+
# REVOKE $_privilege
336+
$custom_unless = "SELECT 1 WHERE NOT EXISTS
337+
( SELECT table_name FROM information_schema.role_table_grants
338+
WHERE grantee = '${role}' AND table_schema ='${schema}'
339+
AND privilege_type = '${_privilege}'
340+
)"
341+
}
242342
}
243343

244-
# This checks if there is a difference between the tables in the
245-
# specified schema and the tables for which the role has the specified
246-
# privilege. It uses the EXCEPT clause which computes the set of rows
247-
# that are in the result of the first SELECT statement but not in the
248-
# result of the second one. It then counts the number of rows from this
249-
# operation. If this number is zero then the role has the specified
250-
# privilege for all tables in the schema and the whole query returns a
251-
# single row, which satisfies the `unless` parameter of Postgresql_psql.
252-
# If this number is not zero then there is at least one table for which
253-
# the role does not have the specified privilege, making it necessary to
254-
# execute the GRANT statement.
255-
$custom_unless = "SELECT 1 FROM (
256-
SELECT table_name
257-
FROM information_schema.tables
258-
WHERE table_schema='${schema}'
259-
EXCEPT DISTINCT
260-
SELECT table_name
261-
FROM information_schema.role_table_grants
262-
WHERE grantee='${role}'
263-
AND table_schema='${schema}'
264-
AND privilege_type='${custom_privilege}'
265-
) P
266-
HAVING count(P.table_name) = 0"
267344
}
268345
'LANGUAGE': {
269346
$unless_privilege = $_privilege ? {
@@ -313,17 +390,18 @@
313390
false => undef,
314391
'custom' => $custom_unless,
315392
default => "SELECT 1 WHERE ${unless_function}('${role}',
316-
'${_granted_object}', '${unless_privilege}')",
393+
'${_granted_object}', '${unless_privilege}') = ${unless_is}",
317394
}
318395

319396
$_onlyif = $onlyif_function ? {
320397
'table_exists' => "SELECT true FROM pg_tables WHERE tablename = '${_togrant_object}'",
321398
'language_exists' => "SELECT true from pg_language WHERE lanname = '${_togrant_object}'",
399+
'role_exists' => "SELECT 1 FROM pg_roles WHERE rolname = '${role}'",
322400
default => undef,
323401
}
324402

325-
$grant_cmd = "GRANT ${_privilege} ON ${_object_type} \"${_togrant_object}\" TO
326-
\"${role}\""
403+
$grant_cmd = sprintf($sql_command, $_privilege, $_object_type, $_togrant_object, $role)
404+
327405
postgresql_psql { "grant:${name}":
328406
command => $grant_cmd,
329407
db => $on_db,

manifests/server/table_grant.pp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
$table,
66
$db,
77
$role,
8+
$ensure = undef,
89
$port = undef,
910
$psql_db = undef,
1011
$psql_user = undef,
1112
$connect_settings = undef,
1213
$onlyif_exists = false,
1314
) {
1415
postgresql::server::grant { "table:${name}":
16+
ensure => $ensure,
1517
role => $role,
1618
db => $db,
1719
port => $port,
@@ -23,4 +25,4 @@
2325
onlyif_exists => $onlyif_exists,
2426
connect_settings => $connect_settings,
2527
}
26-
}
28+
}

0 commit comments

Comments
 (0)