Skip to content

Commit c603966

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

File tree

6 files changed

+389
-88
lines changed

6 files changed

+389
-88
lines changed

README.md

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

11001100
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.
11011101

1102+
##### `ensure`
1103+
1104+
Specifies whether to grant or revoke the privilege. Default is to grant the privilege.
1105+
1106+
Valid values: 'present', 'absent'.
1107+
* 'present' to grant the privilege
1108+
* 'absent' to revoke the privilege
1109+
1110+
Default value: 'present'.
1111+
11021112
#### `connect_settings`
11031113

11041114
Specifies a hash of environment variables used when connecting to a remote server.
@@ -1165,6 +1175,16 @@ By default, the package specified with `package_name` is installed when the exte
11651175

11661176
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.
11671177

1178+
##### `ensure`
1179+
1180+
Specifies whether to grant or revoke the privilege. Default is to grant the privilege.
1181+
1182+
Valid values: 'present', 'absent'.
1183+
* 'present' to grant the privilege
1184+
* 'absent' to revoke the privilege
1185+
1186+
Default value: 'present'.
1187+
11681188
##### `db`
11691189

11701190
Specifies the database to which you are granting access.
@@ -1476,6 +1496,16 @@ Default value: the namevar.
14761496

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

1499+
##### `ensure`
1500+
1501+
Specifies whether to grant or revoke the privilege. Default is to grant the privilege.
1502+
1503+
Valid values: 'present', 'absent'.
1504+
* 'present' to grant the privilege
1505+
* 'absent' to revoke the privilege
1506+
1507+
Default value: 'present'.
1508+
14791509
##### `connect_settings`
14801510

14811511
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: 151 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,31 @@
22
define postgresql::server::grant (
33
String $role,
44
String $db,
5-
Optional[String] $privilege = undef,
6-
String $object_type = 'database',
7-
Optional[String[1]] $object_name = undef,
8-
String $psql_db = $postgresql::server::default_database,
9-
String $psql_user = $postgresql::server::user,
10-
Integer $port = $postgresql::server::port,
11-
Boolean $onlyif_exists = false,
12-
Hash $connect_settings = $postgresql::server::default_connect_settings,
5+
Optional[String] $privilege = undef,
6+
String $object_type = 'database',
7+
Optional[String[1]] $object_name = undef,
8+
String $psql_db = $postgresql::server::default_database,
9+
String $psql_user = $postgresql::server::user,
10+
Integer $port = $postgresql::server::port,
11+
Boolean $onlyif_exists = false,
12+
Hash $connect_settings = $postgresql::server::default_connect_settings,
13+
Enum['present', 'absent'] $ensure = 'present',
1314
) {
1415

16+
case $ensure {
17+
'present': {
18+
$sql_command = 'GRANT %s ON %s "%s" TO "%s"'
19+
$unless_is = true
20+
}
21+
'absent': {
22+
$sql_command = 'REVOKE %s ON %s "%s" FROM "%s"'
23+
$unless_is = false
24+
}
25+
default: {
26+
fail("Unknown value for ensure '${ensure}'.")
27+
}
28+
}
29+
1530
$group = $postgresql::server::group
1631
$psql_path = $postgresql::server::psql_path
1732

@@ -125,43 +140,80 @@
125140
# If this number is not zero then there is at least one sequence for which
126141
# the role does not have the specified privilege, making it necessary to
127142
# execute the GRANT statement.
128-
$custom_unless = "SELECT 1 FROM (
129-
SELECT sequence_name
130-
FROM information_schema.sequences
131-
WHERE sequence_schema='${schema}'
132-
EXCEPT DISTINCT
133-
SELECT object_name as sequence_name
134-
FROM (
135-
SELECT object_schema,
136-
object_name,
137-
grantee,
138-
CASE privs_split
139-
WHEN 'r' THEN 'SELECT'
140-
WHEN 'w' THEN 'UPDATE'
141-
WHEN 'U' THEN 'USAGE'
142-
END AS privilege_type
143-
FROM (
144-
SELECT DISTINCT
145-
object_schema,
146-
object_name,
147-
(regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee,
148-
regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split
149-
FROM (
150-
SELECT n.nspname as object_schema,
151-
c.relname as object_name,
152-
regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs
153-
FROM pg_catalog.pg_class c
154-
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
155-
WHERE c.relkind = 'S'
156-
AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' )
157-
) P1
158-
) P2
159-
) P3
160-
WHERE grantee='${role}'
161-
AND object_schema='${schema}'
162-
AND privilege_type='${custom_privilege}'
163-
) P
164-
HAVING count(P.sequence_name) = 0"
143+
if $ensure == 'present' {
144+
$custom_unless = "SELECT 1 FROM (
145+
SELECT sequence_name
146+
FROM information_schema.sequences
147+
WHERE sequence_schema='${schema}'
148+
EXCEPT DISTINCT
149+
SELECT object_name as sequence_name
150+
FROM (
151+
SELECT object_schema,
152+
object_name,
153+
grantee,
154+
CASE privs_split
155+
WHEN 'r' THEN 'SELECT'
156+
WHEN 'w' THEN 'UPDATE'
157+
WHEN 'U' THEN 'USAGE'
158+
END AS privilege_type
159+
FROM (
160+
SELECT DISTINCT
161+
object_schema,
162+
object_name,
163+
(regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee,
164+
regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split
165+
FROM (
166+
SELECT n.nspname as object_schema,
167+
c.relname as object_name,
168+
regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs
169+
FROM pg_catalog.pg_class c
170+
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
171+
WHERE c.relkind = 'S'
172+
AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' )
173+
) P1
174+
) P2
175+
) P3
176+
WHERE grantee='${role}'
177+
AND object_schema='${schema}'
178+
AND privilege_type='${custom_privilege}'
179+
) P
180+
HAVING count(P.sequence_name) = 0"
181+
} else {
182+
# ensure == absent
183+
$custom_unless = "SELECT 1 FROM (
184+
SELECT object_name as sequence_name
185+
FROM (
186+
SELECT object_schema,
187+
object_name,
188+
grantee,
189+
CASE privs_split
190+
WHEN 'r' THEN 'SELECT'
191+
WHEN 'w' THEN 'UPDATE'
192+
WHEN 'U' THEN 'USAGE'
193+
END AS privilege_type
194+
FROM (
195+
SELECT DISTINCT
196+
object_schema,
197+
object_name,
198+
(regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee,
199+
regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split
200+
FROM (
201+
SELECT n.nspname as object_schema,
202+
c.relname as object_name,
203+
regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs
204+
FROM pg_catalog.pg_class c
205+
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
206+
WHERE c.relkind = 'S'
207+
AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' )
208+
) P1
209+
) P2
210+
) P3
211+
WHERE grantee='${role}'
212+
AND object_schema='${schema}'
213+
AND privilege_type='${custom_privilege}'
214+
) P
215+
HAVING count(P.sequence_name) = 0"
216+
}
165217
}
166218
'TABLE': {
167219
$unless_privilege = $_privilege ? {
@@ -187,37 +239,58 @@
187239
$schema = $object_name
188240

189241
# Again there seems to be no easy way in plain SQL to check if ALL
190-
# PRIVILEGES are granted on a table. By convention we use INSERT
191-
# here to represent ALL PRIVILEGES (truly terrible).
192-
$custom_privilege = $_privilege ? {
193-
'ALL' => 'INSERT',
194-
'ALL PRIVILEGES' => 'INSERT',
195-
default => $_privilege,
242+
# PRIVILEGES are granted on a table.
243+
# There are currently 7 possible priviliges:
244+
# ('SELECT','UPDATE','INSERT','DELETE','TRIGGER','REFERENCES','TRUNCATE')
245+
# This list is consistant from Postgresql 8.0
246+
#
247+
# There are 4 cases to cover, each with it's own distinct unless clause:
248+
# grant ALL
249+
# grant SELECT (or INSERT or DELETE ...)
250+
# revoke ALL
251+
# revoke SELECT (or INSERT or DELETE ...)
252+
253+
if $ensure == 'present' {
254+
if $_privilege == 'ALL' or $_privilege == 'ALL PRIVILEGES' {
255+
# GRANT ALL
256+
$custom_unless = "SELECT 1 FROM
257+
( SELECT tablename FROM pg_catalog.pg_tables
258+
WHERE schemaname = '${schema}' EXCEPT
259+
SELECT table_name FROM
260+
(SELECT table_name,count(privilege_type) FROM information_schema.role_table_grants
261+
WHERE grantee = '${role}' AND table_schema = '${schema}'
262+
AND privilege_type IN ('SELECT','UPDATE','INSERT','DELETE','TRIGGER','REFERENCES','TRUNCATE')
263+
GROUP BY table_name
264+
) AS P WHERE P.count >= 7
265+
) AS TBLS HAVING TBLS.count=0"
266+
267+
} else {
268+
# GRANT $_privilege
269+
$custom_unless = "SELECT 1 FROM
270+
( SELECT tablename FROM pg_catalog.pg_tables
271+
WHERE schemaname = '${schema}' EXCEPT
272+
SELECT table_name FROM
273+
information_schema.role_table_grants
274+
WHERE grantee = '${role}' AND table_schema = '${schema}' AND privilege_type = '${_privilege}'
275+
) AS TBLS HAVING TBLS.count=0"
276+
}
277+
} else {
278+
if $_privilege == 'ALL' or $_privilege == 'ALL PRIVILEGES' {
279+
# REVOKE ALL
280+
$custom_unless = "SELECT 1 FROM
281+
( SELECT table_name FROM information_schema.role_table_grants
282+
WHERE grantee = '${role}' AND table_schema ='${schema}'
283+
) AS TBLS HAVING TBLS.count=0"
284+
} else {
285+
# REVOKE $_privilege
286+
$custom_unless = "SELECT 1 FROM
287+
( SELECT table_name FROM information_schema.role_table_grants
288+
WHERE grantee = '${role}' AND table_schema ='${schema}'
289+
AND privilege_type = '${_privilege}'
290+
) AS TBLS HAVING TBLS.count=0"
291+
}
196292
}
197293

198-
# This checks if there is a difference between the tables in the
199-
# specified schema and the tables for which the role has the specified
200-
# privilege. It uses the EXCEPT clause which computes the set of rows
201-
# that are in the result of the first SELECT statement but not in the
202-
# result of the second one. It then counts the number of rows from this
203-
# operation. If this number is zero then the role has the specified
204-
# privilege for all tables in the schema and the whole query returns a
205-
# single row, which satisfies the `unless` parameter of Postgresql_psql.
206-
# If this number is not zero then there is at least one table for which
207-
# the role does not have the specified privilege, making it necessary to
208-
# execute the GRANT statement.
209-
$custom_unless = "SELECT 1 FROM (
210-
SELECT table_name
211-
FROM information_schema.tables
212-
WHERE table_schema='${schema}'
213-
EXCEPT DISTINCT
214-
SELECT table_name
215-
FROM information_schema.role_table_grants
216-
WHERE grantee='${role}'
217-
AND table_schema='${schema}'
218-
AND privilege_type='${custom_privilege}'
219-
) P
220-
HAVING count(P.table_name) = 0"
221294
}
222295
'LANGUAGE': {
223296
$unless_privilege = $_privilege ? {
@@ -259,8 +332,8 @@
259332
$_unless = $unless_function ? {
260333
false => undef,
261334
'custom' => $custom_unless,
262-
default => "SELECT 1 WHERE ${unless_function}('${role}',
263-
'${_granted_object}', '${unless_privilege}')",
335+
default => "SELECT * FROM ${unless_function}('${role}',
336+
'${_granted_object}', '${unless_privilege}') WHERE ${unless_function} = ${unless_is}",
264337
}
265338

266339
$_onlyif = $onlyif_function ? {
@@ -269,8 +342,8 @@
269342
default => undef,
270343
}
271344

272-
$grant_cmd = "GRANT ${_privilege} ON ${_object_type} \"${_togrant_object}\" TO
273-
\"${role}\""
345+
$grant_cmd = sprintf($sql_command, $_privilege, $_object_type, $_togrant_object, $role)
346+
274347
postgresql_psql { "grant:${name}":
275348
command => $grant_cmd,
276349
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)