diff --git a/manifests/server/grant_role.pp b/manifests/server/grant_role.pp index 6a5d124..0663559 100644 --- a/manifests/server/grant_role.pp +++ b/manifests/server/grant_role.pp @@ -1,51 +1,51 @@ # Define for granting membership to a role. See README.md for more information define postgresql::server::grant_role ( $group, $role, $ensure = 'present', $psql_db = $postgresql::server::default_database, $psql_user = $postgresql::server::user, $port = $postgresql::server::port, $connect_settings = $postgresql::server::default_connect_settings, ) { validate_string($group) validate_string($role) if empty($group) { fail('$group must be set') } if empty($role) { fail('$role must be set') } case $ensure { 'present': { $command = "GRANT \"${group}\" TO \"${role}\"" $unless_comp = '=' } 'absent': { $command = "REVOKE \"${group}\" FROM \"${role}\"" $unless_comp = '!=' } default: { fail("Unknown value for ensure '${ensure}'.") } } postgresql_psql { "grant_role:${name}": command => $command, - unless => "SELECT t.count FROM (SELECT count(*) FROM pg_user AS u JOIN pg_auth_members AS am ON (u.usesysid = am.member) JOIN pg_roles AS r ON (r.oid = am.roleid) WHERE r.rolname = '${group}' AND u.usename = '${role}') AS t WHERE t.count ${unless_comp} 1", + unless => "SELECT 1 WHERE pg_has_role('${role}', '${group}', 'MEMBER') ${unless_comp} true", db => $psql_db, psql_user => $psql_user, port => $port, connect_settings => $connect_settings, } if ! $connect_settings or empty($connect_settings) { Class['postgresql::server']->Postgresql_psql["grant_role:${name}"] } if defined(Postgresql::Server::Role[$role]) { Postgresql::Server::Role[$role]->Postgresql_psql["grant_role:${name}"] } if defined(Postgresql::Server::Role[$group]) { Postgresql::Server::Role[$group]->Postgresql_psql["grant_role:${name}"] } } diff --git a/spec/acceptance/server/grant_role_spec.rb b/spec/acceptance/server/grant_role_spec.rb new file mode 100644 index 0000000..616d86c --- /dev/null +++ b/spec/acceptance/server/grant_role_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper_acceptance' + +describe 'postgresql::server::grant_role:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + it 'should grant a role to a user' do + begin + pp = <<-EOS.unindent + $db = 'grant_role_test' + $user = 'psql_grant_role_tester' + $group = 'test_group' + $password = 'psql_grant_role_pw' + + class { 'postgresql::server': } + + # Since we are not testing pg_hba or any of that, make a local user for ident auth + user { $user: + ensure => present, + } + + postgresql::server::role { $user: + password_hash => postgresql_password($user, $password), + } + + postgresql::server::database { $db: + owner => $user, + require => Postgresql::Server::Role[$user], + } + + # Create a rule for the user + postgresql::server::pg_hba_rule { "allow ${user}": + type => 'local', + database => $db, + user => $user, + auth_method => 'ident', + order => 1, + } + + # Create a role to grant to the user + postgresql::server::role { $group: + db => $db, + login => false, + require => Postgresql::Server::Database[$db], + } + + # Grant the role to the user + postgresql::server::grant_role { "grant_role ${group} to ${user}": + role => $user, + group => $group, + } + EOS + + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + + ## Check that the role was granted to the user + psql('--command="SELECT 1 WHERE pg_has_role(\'psql_grant_role_tester\', \'test_group\', \'MEMBER\') = true" grant_role_test', 'psql_grant_role_tester') do |r| + expect(r.stdout).to match(/\(1 row\)/) + expect(r.stderr).to eq('') + end + end + end + +end diff --git a/spec/unit/defines/server/grant_role_spec.rb b/spec/unit/defines/server/grant_role_spec.rb index 37f3ec7..2a04bef 100644 --- a/spec/unit/defines/server/grant_role_spec.rb +++ b/spec/unit/defines/server/grant_role_spec.rb @@ -1,161 +1,161 @@ require 'spec_helper' describe 'postgresql::server::grant_role', :type => :define do let :pre_condition do "class { 'postgresql::server': }" end let :facts do {:osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('postgis'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let (:title) { 'test' } let (:params) { { :group => 'my_group', :role => 'my_role', } } context "with mandatory arguments only" do it { is_expected.to contain_postgresql_psql("grant_role:#{title}").with({ :command => "GRANT \"#{params[:group]}\" TO \"#{params[:role]}\"", - :unless => "SELECT t.count FROM (SELECT count(*) FROM pg_user AS u JOIN pg_auth_members AS am ON (u.usesysid = am.member) JOIN pg_roles AS r ON (r.oid = am.roleid) WHERE r.rolname = '#{params[:group]}' AND u.usename = '#{params[:role]}') AS t WHERE t.count = 1", + :unless => "SELECT 1 WHERE pg_has_role('#{params[:role]}', '#{params[:group]}', 'MEMBER') = true", }).that_requires('Class[postgresql::server]') } end context "validation" do context "group invalid type" do let (:params) { { :group => ['a', 'b'], :role => 'r', } } it { expect { catalogue }.to raise_error(Puppet::Error, /is not a string/) } end context "role invalid type" do let (:params) { { :group => 'g', :role => true, } } it { expect { catalogue }.to raise_error(Puppet::Error, /is not a string/) } end context "group empty" do let (:params) { { :group => '', :role => 'r', } } it { expect { catalogue }.to raise_error(/\$group must be set/) } end context "role empty" do let (:params) { { :group => 'g', :role => :undef, } } it { expect { catalogue }.to raise_error(/\$role must be set/) } end end context "with db arguments" do let (:params) { super().merge({ :psql_db => 'postgres', :psql_user => 'postgres', :port => '5432', }) } it { is_expected.to contain_postgresql_psql("grant_role:#{title}").with({ :command => "GRANT \"#{params[:group]}\" TO \"#{params[:role]}\"", - :unless => "SELECT t.count FROM (SELECT count(*) FROM pg_user AS u JOIN pg_auth_members AS am ON (u.usesysid = am.member) JOIN pg_roles AS r ON (r.oid = am.roleid) WHERE r.rolname = '#{params[:group]}' AND u.usename = '#{params[:role]}') AS t WHERE t.count = 1", + :unless => "SELECT 1 WHERE pg_has_role('#{params[:role]}', '#{params[:group]}', 'MEMBER') = true", :db => params[:psql_db], :psql_user => params[:psql_user], :port => params[:port], }).that_requires('Class[postgresql::server]') } end context "with ensure => absent" do let (:params) { super().merge({ :ensure => 'absent', }) } it { is_expected.to contain_postgresql_psql("grant_role:#{title}").with({ :command => "REVOKE \"#{params[:group]}\" FROM \"#{params[:role]}\"", - :unless => "SELECT t.count FROM (SELECT count(*) FROM pg_user AS u JOIN pg_auth_members AS am ON (u.usesysid = am.member) JOIN pg_roles AS r ON (r.oid = am.roleid) WHERE r.rolname = '#{params[:group]}' AND u.usename = '#{params[:role]}') AS t WHERE t.count != 1", + :unless => "SELECT 1 WHERE pg_has_role('#{params[:role]}', '#{params[:group]}', 'MEMBER') != true", }).that_requires('Class[postgresql::server]') } end context "with ensure => invalid" do let (:params) { super().merge({ :ensure => 'invalid', }) } it { expect { catalogue }.to raise_error(Puppet::Error, /Unknown value for ensure/) } end context "with user defined" do let :pre_condition do "class { 'postgresql::server': } postgresql::server::role { '#{params[:role]}': }" end it { is_expected.to contain_postgresql_psql("grant_role:#{title}").that_requires("Postgresql::Server::Role[#{params[:role]}]") } it { is_expected.not_to contain_postgresql_psql("grant_role:#{title}").that_requires("Postgresql::Server::Role[#{params[:group]}]") } end context "with group defined" do let :pre_condition do "class { 'postgresql::server': } postgresql::server::role { '#{params[:group]}': }" end it { is_expected.to contain_postgresql_psql("grant_role:#{title}").that_requires("Postgresql::Server::Role[#{params[:group]}]") } it { is_expected.not_to contain_postgresql_psql("grant_role:#{title}").that_requires("Postgresql::Server::Role[#{params[:role]}]") } end context "with connect_settings" do let (:params) { super().merge({ :connect_settings => { 'PGHOST' => 'postgres-db-server' }, }) } it { is_expected.to contain_postgresql_psql("grant_role:#{title}").with_connect_settings( { 'PGHOST' => 'postgres-db-server' } ) } it { is_expected.not_to contain_postgresql_psql("grant_role:#{title}").that_requires('Class[postgresql::server]') } end end