|
27 | 27 | Integer $port = $postgresql::server::port,
|
28 | 28 | Boolean $onlyif_exists = false,
|
29 | 29 | Hash $connect_settings = $postgresql::server::default_connect_settings,
|
| 30 | + Enum['present', |
| 31 | + 'absent' |
| 32 | + ] $ensure = 'present', |
30 | 33 | ) {
|
31 | 34 |
|
| 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 | + |
32 | 47 | $group = $postgresql::server::group
|
33 | 48 | $psql_path = $postgresql::server::psql_path
|
34 | 49 |
|
|
81 | 96 | }
|
82 | 97 | $unless_function = 'has_database_privilege'
|
83 | 98 | $on_db = $psql_db
|
84 |
| - $onlyif_function = undef |
| 99 | + $onlyif_function = $ensure ? { |
| 100 | + default => undef, |
| 101 | + 'absent' => 'role_exists', |
| 102 | + } |
85 | 103 | }
|
86 | 104 | 'SCHEMA': {
|
87 | 105 | $unless_privilege = $_privilege ? {
|
|
149 | 167 | # If this number is not zero then there is at least one sequence for which
|
150 | 168 | # the role does not have the specified privilege, making it necessary to
|
151 | 169 | # 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 | + } |
189 | 242 | }
|
190 | 243 | 'TABLE': {
|
191 | 244 | $unless_privilege = $_privilege ? {
|
|
233 | 286 | $schema = $object_name
|
234 | 287 |
|
235 | 288 | # 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 | + } |
242 | 343 | }
|
243 | 344 |
|
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" |
267 | 345 | }
|
268 | 346 | 'LANGUAGE': {
|
269 | 347 | $unless_privilege = $_privilege ? {
|
|
313 | 391 | false => undef,
|
314 | 392 | 'custom' => $custom_unless,
|
315 | 393 | default => "SELECT 1 WHERE ${unless_function}('${role}',
|
316 |
| - '${_granted_object}', '${unless_privilege}')", |
| 394 | + '${_granted_object}', '${unless_privilege}') = ${unless_is}", |
317 | 395 | }
|
318 | 396 |
|
319 | 397 | $_onlyif = $onlyif_function ? {
|
320 | 398 | 'table_exists' => "SELECT true FROM pg_tables WHERE tablename = '${_togrant_object}'",
|
321 | 399 | 'language_exists' => "SELECT true from pg_language WHERE lanname = '${_togrant_object}'",
|
| 400 | + 'role_exists' => "SELECT 1 FROM pg_roles WHERE rolname = '${role}'", |
322 | 401 | default => undef,
|
323 | 402 | }
|
324 | 403 |
|
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 | + |
327 | 406 | postgresql_psql { "grant:${name}":
|
328 | 407 | command => $grant_cmd,
|
329 | 408 | db => $on_db,
|
|
0 commit comments