Skip to content

Commit 34b266d

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

File tree

6 files changed

+409
-81
lines changed

6 files changed

+409
-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: 149 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,23 @@
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'
32+
] $ensure = 'present',
3033
) {
3134

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

@@ -81,7 +96,10 @@
8196
}
8297
$unless_function = 'has_database_privilege'
8398
$on_db = $psql_db
84-
$onlyif_function = undef
99+
$onlyif_function = $ensure ? {
100+
default => undef,
101+
'absent' => 'role_exists',
102+
}
85103
}
86104
'SCHEMA': {
87105
$unless_privilege = $_privilege ? {
@@ -149,43 +167,78 @@
149167
# If this number is not zero then there is at least one sequence for which
150168
# the role does not have the specified privilege, making it necessary to
151169
# 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"
170+
if $ensure == 'present' {
171+
$custom_unless = "SELECT 1 WHERE NOT EXISTS (
172+
SELECT sequence_name
173+
FROM information_schema.sequences
174+
WHERE sequence_schema='${schema}'
175+
EXCEPT DISTINCT
176+
SELECT object_name as sequence_name
177+
FROM (
178+
SELECT object_schema,
179+
object_name,
180+
grantee,
181+
CASE privs_split
182+
WHEN 'r' THEN 'SELECT'
183+
WHEN 'w' THEN 'UPDATE'
184+
WHEN 'U' THEN 'USAGE'
185+
END AS privilege_type
186+
FROM (
187+
SELECT DISTINCT
188+
object_schema,
189+
object_name,
190+
(regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee,
191+
regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split
192+
FROM (
193+
SELECT n.nspname as object_schema,
194+
c.relname as object_name,
195+
regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs
196+
FROM pg_catalog.pg_class c
197+
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
198+
WHERE c.relkind = 'S'
199+
AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' )
200+
) P1
201+
) P2
202+
) P3
203+
WHERE grantee='${role}'
204+
AND object_schema='${schema}'
205+
AND privilege_type='${custom_privilege}'
206+
)"
207+
} else {
208+
# ensure == absent
209+
$custom_unless = "SELECT 1 WHERE NOT EXISTS (
210+
SELECT object_name as sequence_name
211+
FROM (
212+
SELECT object_schema,
213+
object_name,
214+
grantee,
215+
CASE privs_split
216+
WHEN 'r' THEN 'SELECT'
217+
WHEN 'w' THEN 'UPDATE'
218+
WHEN 'U' THEN 'USAGE'
219+
END AS privilege_type
220+
FROM (
221+
SELECT DISTINCT
222+
object_schema,
223+
object_name,
224+
(regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee,
225+
regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split
226+
FROM (
227+
SELECT n.nspname as object_schema,
228+
c.relname as object_name,
229+
regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs
230+
FROM pg_catalog.pg_class c
231+
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
232+
WHERE c.relkind = 'S'
233+
AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' )
234+
) P1
235+
) P2
236+
) P3
237+
WHERE grantee='${role}'
238+
AND object_schema='${schema}'
239+
AND privilege_type='${custom_privilege}'
240+
)"
241+
}
189242
}
190243
'TABLE': {
191244
$unless_privilege = $_privilege ? {
@@ -233,37 +286,62 @@
233286
$schema = $object_name
234287

235288
# 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,
289+
# PRIVILEGES are granted on a table.
290+
# There are currently 7 possible priviliges:
291+
# ('SELECT','UPDATE','INSERT','DELETE','TRIGGER','REFERENCES','TRUNCATE')
292+
# This list is consistant from Postgresql 8.0
293+
#
294+
# There are 4 cases to cover, each with it's own distinct unless clause:
295+
# grant ALL
296+
# grant SELECT (or INSERT or DELETE ...)
297+
# revoke ALL
298+
# revoke SELECT (or INSERT or DELETE ...)
299+
300+
if $ensure == 'present' {
301+
if $_privilege == 'ALL' or $_privilege == 'ALL PRIVILEGES' {
302+
# GRANT ALL
303+
$custom_unless = "SELECT 1 WHERE NOT EXISTS
304+
( SELECT 1 FROM pg_catalog.pg_tables AS t,
305+
(VALUES ('SELECT'), ('UPDATE'), ('INSERT'), ('DELETE'), ('TRIGGER'), ('REFERENCES'), ('TRUNCATE')) AS p(privilege_type)
306+
WHERE t.schemaname = '${schema}'
307+
AND NOT EXISTS (
308+
SELECT 1 FROM information_schema.role_table_grants AS g
309+
WHERE g.grantee = '${role}'
310+
AND g.table_schema = '${schema}'
311+
AND g.privilege_type = p.privilege_type
312+
)
313+
)"
314+
315+
} else {
316+
# GRANT $_privilege
317+
$custom_unless = "SELECT 1 WHERE NOT EXISTS
318+
( SELECT 1 FROM pg_catalog.pg_tables AS t
319+
WHERE t.schemaname = '${schema}'
320+
AND NOT EXISTS (
321+
SELECT 1 FROM information_schema.role_table_grants AS g
322+
WHERE g.grantee = '${role}'
323+
AND g.table_schema = '${schema}'
324+
AND g.privilege_type = '${_privilege}'
325+
)
326+
)"
327+
}
328+
} else {
329+
if $_privilege == 'ALL' or $_privilege == 'ALL PRIVILEGES' {
330+
# REVOKE ALL
331+
$custom_unless = "SELECT 1 WHERE NOT EXISTS
332+
( SELECT table_name FROM information_schema.role_table_grants
333+
WHERE grantee = '${role}' AND table_schema ='${schema}'
334+
)"
335+
} else {
336+
# REVOKE $_privilege
337+
$custom_unless = "SELECT 1 WHERE NOT EXISTS
338+
( SELECT table_name FROM information_schema.role_table_grants
339+
WHERE grantee = '${role}' AND table_schema ='${schema}'
340+
AND privilege_type = '${_privilege}'
341+
)"
342+
}
242343
}
243344

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"
267345
}
268346
'LANGUAGE': {
269347
$unless_privilege = $_privilege ? {
@@ -313,17 +391,18 @@
313391
false => undef,
314392
'custom' => $custom_unless,
315393
default => "SELECT 1 WHERE ${unless_function}('${role}',
316-
'${_granted_object}', '${unless_privilege}')",
394+
'${_granted_object}', '${unless_privilege}') = ${unless_is}",
317395
}
318396

319397
$_onlyif = $onlyif_function ? {
320398
'table_exists' => "SELECT true FROM pg_tables WHERE tablename = '${_togrant_object}'",
321399
'language_exists' => "SELECT true from pg_language WHERE lanname = '${_togrant_object}'",
400+
'role_exists' => "SELECT 1 FROM pg_roles WHERE rolname = '${role}'",
322401
default => undef,
323402
}
324403

325-
$grant_cmd = "GRANT ${_privilege} ON ${_object_type} \"${_togrant_object}\" TO
326-
\"${role}\""
404+
$grant_cmd = sprintf($sql_command, $_privilege, $_object_type, $_togrant_object, $role)
405+
327406
postgresql_psql { "grant:${name}":
328407
command => $grant_cmd,
329408
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)