Skip to content

Commit

Permalink
Support setting default_privileges on all schemas
Browse files Browse the repository at this point in the history
The Postgres default is for the absent specification of a schema name
when altering default privileges to apply to all schemas.
Support that behaviour, but keep the current default behaviour for
an unset schema parameter.
  • Loading branch information
fish-face committed Oct 18, 2021
1 parent c768dec commit 6aaa1cf
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 11 deletions.
22 changes: 15 additions & 7 deletions manifests/server/default_privileges.pp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# @param db Specifies the database to which you are granting access.
# @param object_type Specify target object type: 'FUNCTIONS', 'ROUTINES', 'SEQUENCES', 'TABLES', 'TYPES'.
# @param privilege Specifies comma-separated list of privileges to grant. Valid options: depends on object type.
# @param schema Target schema. Defaults to 'public'.
# @param schema Target schema. Defaults to 'public'. Can be set to '' to apply to all schemas.
# @param psql_db Defines the database to execute the grant against. This should not ordinarily be changed from the default.
# @param psql_user Specifies the OS user for running psql. Default value: The default user for the module, usually 'postgres'.
# @param psql_path Specifies the OS user for running psql. Default value: The default user for the module, usually 'postgres'.
Expand Down Expand Up @@ -52,11 +52,11 @@
case $ensure {
default: {
# default is 'present'
$sql_command = 'ALTER DEFAULT PRIVILEGES%s IN SCHEMA %s GRANT %s ON %s TO "%s"'
$sql_command = 'ALTER DEFAULT PRIVILEGES%s%s GRANT %s ON %s TO "%s"'
$unless_is = true
}
'absent': {
$sql_command = 'ALTER DEFAULT PRIVILEGES%s IN SCHEMA %s REVOKE %s ON %s FROM "%s"'
$sql_command = 'ALTER DEFAULT PRIVILEGES%s%s REVOKE %s ON %s FROM "%s"'
$unless_is = false
}
}
Expand All @@ -80,6 +80,14 @@
$_check_target_role = ''
}

if $schema != '' {
$_schema = " IN SCHEMA $schema"
$_check_schema = " AND nspname = '$schema'"
} else {
$_schema = ''
$_check_schema = ' AND nspname IS NULL'
}

## Munge the input values
$_object_type = upcase($object_type)
$_privilege = upcase($privilege)
Expand Down Expand Up @@ -138,12 +146,12 @@
}

$_unless = $ensure ? {
'absent' => "SELECT 1 WHERE NOT EXISTS (SELECT * FROM pg_default_acl AS da JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '%s=%s%s' = ANY (defaclacl) AND nspname = '%s' and defaclobjtype = '%s')",
default => "SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '%s=%s%s' = ANY (defaclacl) AND nspname = '%s' and defaclobjtype = '%s')"
'absent' => "SELECT 1 WHERE NOT EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '%s=%s%s' = ANY (defaclacl)%s and defaclobjtype = '%s')",
default => "SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '%s=%s%s' = ANY (defaclacl)%s and defaclobjtype = '%s')"
}

$unless_cmd = sprintf($_unless, $role, $_check_privilege, $_check_target_role, $schema, $_check_type)
$grant_cmd = sprintf($sql_command, $_target_role, $schema, $_privilege, $_object_type, $role)
$unless_cmd = sprintf($_unless, $role, $_check_privilege, $_check_target_role, $_check_schema, $_check_type)
$grant_cmd = sprintf($sql_command, $_target_role, $_schema, $_privilege, $_object_type, $role)

postgresql_psql { "default_privileges:${name}":
command => $grant_cmd,
Expand Down
86 changes: 85 additions & 1 deletion spec/acceptance/server/default_privileges_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

# Check that the default privileges were revoked
let(:check_command) do
"SELECT * FROM pg_default_acl a JOIN pg_namespace b ON a.defaclnamespace = b.oid WHERE '#{user}=arwdDxt' = ANY (defaclacl) AND nspname = 'public' and defaclobjtype = 'r';"
"SELECT * FROM pg_default_acl a LEFT JOIN pg_namespace b ON a.defaclnamespace = b.oid WHERE '#{user}=arwdDxt' = ANY (defaclacl) AND nspname = 'public' and defaclobjtype = 'r';"
end

let(:pp_one) do
Expand Down Expand Up @@ -167,6 +167,67 @@ class { 'postgresql::server': }
MANIFEST
end

let(:all_schemas_check_command) do
"SELECT * FROM pg_default_acl a WHERE '#{user}=arwdDxt' = ANY (defaclacl) AND defaclnamespace = 0 and defaclobjtype = 'r';"
end

let(:pp_unset_schema) do
<<-MANIFEST.unindent
$db = #{db}
$user = #{user}
$group = #{group}
$password = #{password}
class { 'postgresql::server': }
postgresql::server::role { $user:
password_hash => postgresql::postgresql_password($user, $password),
}
postgresql::server::database { $db:
require => Postgresql::Server::Role[$user],
}
# Set default privileges on tables
postgresql::server::default_privileges { "alter default privileges grant all on tables to ${user}":
db => $db,
role => $user,
privilege => 'ALL',
object_type => 'TABLES',
schema => '',
require => Postgresql::Server::Database[$db],
}
MANIFEST
end
let(:pp_unset_schema_revoke) do
<<-MANIFEST
$db = #{db}
$user = #{user}
$group = #{group}
$password = #{password}
class { 'postgresql::server': }
postgresql::server::role { $user:
password_hash => postgresql::postgresql_password($user, $password),
}
postgresql::server::database { $db:
require => Postgresql::Server::Role[$user],
}
# Removes default privileges on tables
postgresql::server::default_privileges { "alter default privileges revoke all on tables for ${user}":
db => $db,
role => $user,
privilege => 'ALL',
object_type => 'TABLES',
schema => '',
ensure => 'absent',
require => Postgresql::Server::Database[$db],
}
MANIFEST
end

it 'grants default privileges to an user' do
if Gem::Version.new(postgresql_version) >= Gem::Version.new('9.6')
idempotent_apply(pp_one)
Expand Down Expand Up @@ -212,4 +273,27 @@ class { 'postgresql::server': }
end
end
end

it 'grants default privileges on all schemas to a user' do
if Gem::Version.new(postgresql_version) >= Gem::Version.new('9.6')
idempotent_apply(pp_unset_schema)

psql("--command=\"SET client_min_messages = 'error';#{all_schemas_check_command}\" --db=#{db}") do |r|
expect(r.stdout).to match(%r{\(1 row\)})
expect(r.stderr).to eq('')
end
end
end

it 'revokes default privileges on all schemas for a user' do
if Gem::Version.new(postgresql_version) >= Gem::Version.new('9.6')
apply_manifest(pp_unset_schema, catch_failures: true)
apply_manifest(pp_unset_schema_revoke, expect_changes: true)

psql("--command=\"SET client_min_messages = 'error';#{all_schemas_check_command}\" --db=#{db}") do |r|
expect(r.stdout).to match(%r{\(0 rows\)})
expect(r.stderr).to eq('')
end
end
end
end
32 changes: 29 additions & 3 deletions spec/unit/defines/server/default_privileges_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
# rubocop:disable Layout/LineLength
is_expected.to contain_postgresql_psql('default_privileges:test')
.with_command('ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO "test"')
.with_unless("SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE 'test=arwdDxt' = ANY (defaclacl) AND nspname = 'public' and defaclobjtype = 'r')")
.with_unless("SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE 'test=arwdDxt' = ANY (defaclacl) AND nspname = 'public' and defaclobjtype = 'r')")
# rubocop:enable Layout/LineLength
end
end
Expand Down Expand Up @@ -222,7 +222,33 @@
# rubocop:disable Layout/LineLength
is_expected.to contain_postgresql_psql('default_privileges:test')
.with_command('ALTER DEFAULT PRIVILEGES IN SCHEMA my_schema GRANT ALL ON TABLES TO "test"')
.with_unless("SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE 'test=arwdDxt' = ANY (defaclacl) AND nspname = 'my_schema' and defaclobjtype = 'r')")
.with_unless("SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE 'test=arwdDxt' = ANY (defaclacl) AND nspname = 'my_schema' and defaclobjtype = 'r')")
# rubocop:enable Layout/LineLength
end
end

context 'with unset schema name' do
let :params do
{
db: 'test',
role: 'test',
privilege: 'all',
object_type: 'tables',
schema: ''
}
end

let :pre_condition do
"class {'postgresql::server':}"
end

it { is_expected.to compile.with_all_deps }
it { is_expected.to contain_postgresql__server__default_privileges('test') }
it do
# rubocop:disable Layout/LineLength
is_expected.to contain_postgresql_psql('default_privileges:test')
.with_command('ALTER DEFAULT PRIVILEGES GRANT ALL ON TABLES TO "test"')
.with_unless("SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE 'test=arwdDxt' = ANY (defaclacl) AND nspname IS NULL and defaclobjtype = 'r')")
# rubocop:enable Layout/LineLength
end
end
Expand Down Expand Up @@ -278,7 +304,7 @@ class {'postgresql::server':}
# rubocop:disable Layout/LineLength
is_expected.to contain_postgresql_psql('default_privileges:test')
.with_command('ALTER DEFAULT PRIVILEGES FOR ROLE target IN SCHEMA public GRANT ALL ON TABLES TO "test"')
.with_unless("SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE 'test=arwdDxt/target' = ANY (defaclacl) AND nspname = 'public' and defaclobjtype = 'r')")
.with_unless("SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE 'test=arwdDxt/target' = ANY (defaclacl) AND nspname = 'public' and defaclobjtype = 'r')")
# rubocop:enable Layout/LineLength
end
end
Expand Down

0 comments on commit 6aaa1cf

Please sign in to comment.