Split database_grant up

The code to grant permissions databases and their objects has been
abstracted to `postgresql::grant` and is used by both
`postgresql::database_grant` and `postgresql::table_grant`
This commit is contained in:
Hunter Haugen 2013-07-16 12:30:39 -07:00
parent 2e0455ffdf
commit a37eaa053b
4 changed files with 174 additions and 39 deletions

View file

@ -15,50 +15,21 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# TODO: in mysql module, the grant resource name might look like this: 'user@host/dbname';
# I think that the API for the resource type should split these up, because it's
# easier / safer to recombine them for mysql than it is to parse them for other
# databases. Also, in the mysql module, the hostname portion of that string
# affects the user's ability to connect from remote hosts. In postgres this is
# managed via pg_hba.conf; not sure if we want to try to reconcile that difference
# in the modules or not.
define postgresql::database_grant(
# TODO: mysql supports an array of privileges here. We should do that if we
# port this to ruby.
$privilege,
$db,
$role,
$psql_db = $postgresql::params::user,
$psql_user = $postgresql::params::user
$psql_db = undef,
$psql_user = undef
) {
include postgresql::params
Postgresql_psql {
psql_user => $postgresql::params::user,
psql_group => $postgresql::params::group,
psql_path => $postgresql::params::psql_path,
}
# TODO: FIXME: only works on databases, due to using has_database_privilege
# TODO: this is a terrible hack; if they pass "ALL" as the desired privilege,
# we need a way to test for it--and has_database_privilege does not recognize
# 'ALL' as a valid privilege name. So we probably need to hard-code a mapping
# between 'ALL' and the list of actual privileges that it entails, and loop
# over them to check them. That sort of thing will probably need to wait until
# we port this over to ruby, so, for now, we're just going to assume that if
# they have "CREATE" privileges on a database, then they have "ALL". (I told
# you that it was terrible!)
$unless_privilege = $privilege ? {
'ALL' => 'CREATE',
default => $privilege,
}
postgresql_psql {"GRANT ${privilege} ON database \"${db}\" TO \"${role}\"":
db => $psql_db,
psql_user => $psql_user,
unless => "SELECT 1 WHERE has_database_privilege('${role}', '${db}', '${unless_privilege}')",
postgresql::grant { "database:${name}":
role => $role,
db => $db,
privilege => $privilege,
object_type => 'DATABASE',
object_name => $db,
psql_db => $psql_db,
psql_user => $psql_user,
}
}

77
manifests/grant.pp Normal file
View file

@ -0,0 +1,77 @@
# Resource postgresql::grant
#
# TODO: in mysql module, the grant resource name might look like this: 'user@host/dbname';
# I think that the API for the resource type should split these up, because it's
# easier / safer to recombine them for mysql than it is to parse them for other
# databases. Also, in the mysql module, the hostname portion of that string
# affects the user's ability to connect from remote hosts. In postgres this is
# managed via pg_hba.conf; not sure if we want to try to reconcile that difference
# in the modules or not.
define postgresql::grant (
$role,
$db,
# TODO: mysql supports an array of privileges here. We should do that if we
# port this to ruby.
$privilege = undef,
$object_type = 'database',
$object_name = $db,
$psql_db = $postgresql::params::user,
$psql_user = $postgresql::params::user
) {
## Munge the input values
$_object_type = upcase($object_type)
$_privilege = upcase($privilege)
## Validate that the object type is known
validate_string($_object_type,
#'COLUMN',
'DATABASE',
#'FOREIGN SERVER',
#'FOREIGN DATA WRAPPER',
#'FUNCTION',
#'PROCEDURAL LANGUAGE',
#'SCHEMA',
#'SEQUENCE',
'TABLE',
#'TABLESPACE',
#'VIEW',
)
## Validate that the object type's privilege is acceptable
case $_object_type {
'DATABASE': {
validate_string($_privilege,'CREATE','CONNECT','TEMPORARY','TEMP','ALL','ALL PRIVILEGES')
$unless_function = 'has_database_privilege'
$on_db = $psql_db
}
'TABLE': {
validate_string($_privilege,'SELECT','INSERT','UPDATE','REFERENCES','ALL','ALL PRIVILEGES')
$unless_function = 'has_table_privilege'
$on_db = $db
}
default: {
fail("Missing privilege validation for object type ${_object_type}")
}
}
# TODO: this is a terrible hack; if they pass "ALL" as the desired privilege,
# we need a way to test for it--and has_database_privilege does not recognize
# 'ALL' as a valid privilege name. So we probably need to hard-code a mapping
# between 'ALL' and the list of actual privileges that it entails, and loop
# over them to check them. That sort of thing will probably need to wait until
# we port this over to ruby, so, for now, we're just going to assume that if
# they have "CREATE" privileges on a database, then they have "ALL". (I told
# you that it was terrible!)
$unless_privilege = $_privilege ? {
'ALL' => 'CREATE',
default => $_privilege,
}
postgresql_psql { "GRANT ${_privilege} ON ${_object_type} \"${object_name}\" TO \"${role}\"":
db => $on_db,
psql_user => $psql_user,
psql_group => $postgresql::params::group,
psql_path => $postgresql::params::psql_path,
unless => "SELECT 1 WHERE ${unless_function}('${role}', '${object_name}', '${unless_privilege}')",
}
}

20
manifests/table_grant.pp Normal file
View file

@ -0,0 +1,20 @@
# Resource postgresql::table_grant
define postgresql::table_grant(
$privilege,
$table,
$db,
$role,
$psql_db = undef,
$psql_user = undef
) {
include postgresql::params
postgresql::grant { "table:${name}":
role => $role,
db => $db,
privilege => $privilege,
object_type => 'TABLE',
object_name => $table,
psql_db => $psql_db,
psql_user => $psql_user,
}
}

View file

@ -295,6 +295,73 @@ describe 'install:' do
end
end
describe 'postgresql::table_grant' do
it 'should grant access so a user can insert in a table' do
begin
pp = <<-EOS
$db = 'table_grant'
$user = 'psql_table_tester'
$password = 'psql_table_pw'
include 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::database_user { $user:
password_hash => postgresql_password($user, $password),
require => [
Class['postgresql::server'],
User[$user],
],
}
postgresql::database { $db:
require => Class['postgresql::server'],
}
postgresql_psql { 'Create testing table':
command => 'CREATE TABLE "test_table" (field integer NOT NULL)',
db => $db,
unless => "SELECT * FROM pg_tables WHERE tablename = 'test_table'",
require => Postgresql::Database[$db],
}
postgresql::table_grant { 'grant insert test':
privilege => 'INSERT',
table => 'test_table',
db => $db,
role => $user,
require => [
Postgresql::Database[$db],
Postgresql::Database_user[$user],
Postgresql_psql['Create testing table'],
],
}
EOS
puppet_apply(pp) do |r|
r.exit_code.should_not == 1
end
puppet_apply(pp) do |r|
r.exit_code.should be_zero
end
## Check that the user can create a table in the database
#psql('--command="create table foo (foo int)" postgres', 'psql_grant_tester') do |r|
# r.stdout.should =~ /CREATE TABLE/
# r.stderr.should be_empty
# r.exit_code.should == 0
#end
ensure
#psql('--command="drop table foo" postgres', 'psql_grant_tester')
end
end
end
describe 'postgresql::validate_db_connections' do
it 'should run puppet with no changes declared if database connectivity works' do
pp = <<-EOS