Skip to content

Commit 00f3758

Browse files
author
Morgan Haskel
committed
Merge pull request #79 from cyberious/LoginPermissions
FM-2298 and FM-2299 update Login and User to take hash of permissions
2 parents a3c800c + 4010ba2 commit 00f3758

File tree

10 files changed

+341
-64
lines changed

10 files changed

+341
-64
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# === Defined Parser Function: sqlserver_validate_hash_uniq_values
2+
#
3+
# [args*] A hash, that contains string or string[] for values
4+
#
5+
# @raise [Puppet::ParserError] When duplicates are found
6+
#
7+
module Puppet::Parser::Functions
8+
newfunction(:sqlserver_validate_hash_uniq_values) do |arguments|
9+
10+
raise(Puppet::ParseError, 'Expect a Hash as an argument') unless arguments[0].is_a?(Hash)
11+
12+
value = arguments[0].each_value.collect { |v| v }.flatten
13+
14+
total_count = value.count
15+
uniq_count = value.uniq.count
16+
msg = arguments[1] ? arguments[1] : "Duplicate values passed to hash #{value}"
17+
if uniq_count != total_count
18+
raise(Puppet::ParseError, msg)
19+
end
20+
end
21+
end

manifests/login.pp

+44-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
# @see http://technet.microsoft.com/en-us/library/ms189751(v=sql.110).aspx Create Login
4646
# @see http://technet.microsoft.com/en-us/library/ms189828(v=sql.110).aspx Alter Login
4747
#
48+
# [permissions]
49+
# A hash of permissions that should be managed for the login. Valid keys are 'GRANT', 'GRANT_WITH_OPTION', 'DENY' or 'REVOKE'. Valid values must be an array of Strings i.e. {'GRANT' => ['CONNECT SQL', 'CREATE ANY DATABASE'] }
50+
#
51+
##
4852
define sqlserver::login (
4953
$login = $title,
5054
$instance = 'MSSQLSERVER',
@@ -57,6 +61,7 @@
5761
$check_expiration = false,
5862
$check_policy = true,
5963
$disabled = false,
64+
$permissions = { },
6065
) {
6166

6267
sqlserver_validate_instance_name($instance)
@@ -67,15 +72,52 @@
6772
fail ('Can not have check expiration enabled when check_policy is disabled')
6873
}
6974

70-
$create_delete = $ensure ? {
75+
$_create_delete = $ensure ? {
7176
present => 'create',
7277
absent => 'delete',
7378
}
7479

7580
sqlserver_tsql{ "login-${instance}-${login}":
7681
instance => $instance,
77-
command => template("sqlserver/${create_delete}/login.sql.erb"),
82+
command => template("sqlserver/${_create_delete}/login.sql.erb"),
7883
onlyif => template('sqlserver/query/login_exists.sql.erb'),
7984
require => Sqlserver::Config[$instance]
8085
}
86+
87+
if $ensure == present {
88+
validate_hash($permissions)
89+
$_upermissions = sqlserver_upcase($permissions)
90+
sqlserver_validate_hash_uniq_values($_upermissions, "Duplicate permissions found for sqlserver::login[${title}]")
91+
92+
Sqlserver::Login::Permissions{
93+
login => $login,
94+
instance => $instance,
95+
require => Sqlserver_tsql["login-${instance}-${login}"]
96+
}
97+
if has_key($_upermissions, 'GRANT') and is_array($_upermissions['GRANT']) {
98+
sqlserver::login::permissions{ "Sqlserver::Login[${title}]-GRANT-${login}":
99+
state => 'GRANT',
100+
permissions => $_upermissions['GRANT'],
101+
}
102+
}
103+
if has_key($_upermissions, 'DENY') and is_array($_upermissions['DENY']) {
104+
sqlserver::login::permissions{ "Sqlserver::Login[${title}]-DENY-${login}":
105+
state => 'DENY',
106+
permissions => $_upermissions['DENY'],
107+
}
108+
}
109+
if has_key($_upermissions, 'REVOKE') and is_array($_upermissions['REVOKE']) {
110+
sqlserver::login::permissions{ "Sqlserver::Login[${title}]-REVOKE-${login}":
111+
state => 'REVOKE',
112+
permissions => $_upermissions['REVOKE'],
113+
}
114+
}
115+
if has_key($_upermissions, 'GRANT_WITH_OPTION') and is_array($_upermissions['GRANT_WITH_OPTION']) {
116+
sqlserver::login::permissions{ "Sqlserver::Login[${title}]-GRANT-WITH_GRANT_OPTION-${login}":
117+
state => 'GRANT',
118+
with_grant_option => true,
119+
permissions => $_upermissions['GRANT_WITH_OPTION'],
120+
}
121+
}
122+
}
81123
}

manifests/login/permission.pp renamed to manifests/login/permissions.pp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
##
2-
# == Define Resource Type: sqlserver::login::permission#
2+
# == Define Resource Type: sqlserver::login::permissions#
33
#
44
# === Requirement/Dependencies:
55
#
@@ -20,7 +20,7 @@
2020
# The name of the instance where the user and database exists. Defaults to 'MSSQLSERVER'
2121
#
2222
##
23-
define sqlserver::login::permission (
23+
define sqlserver::login::permissions (
2424
$login,
2525
$permissions,
2626
$state = 'GRANT',

manifests/user.pp

+41
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
# [password]
3535
# The password for the user, can only be used when the database is a contained database.
3636
#
37+
# [permissions]
38+
# A hash of permissions that should be managed for the user. Valid keys are 'GRANT', 'GRANT_WITH_OPTION', 'DENY' or 'REVOKE'. Valid values must be an array of Strings i.e. {'GRANT' => ['SELECT', 'INSERT'] }
39+
#
3740
##
3841
define sqlserver::user (
3942
$database,
@@ -43,6 +46,7 @@
4346
$instance = 'MSSQLSERVER',
4447
$login = undef,
4548
$password = undef,
49+
$permissions = { },
4650
)
4751
{
4852
sqlserver_validate_instance_name($instance)
@@ -69,4 +73,41 @@
6973
require => Sqlserver::Config[$instance]
7074
}
7175

76+
if $ensure == present {
77+
validate_hash($permissions)
78+
$_upermissions = sqlserver_upcase($permissions)
79+
sqlserver_validate_hash_uniq_values($_upermissions, "Duplicate permissions found for sqlserver::user[${title}]")
80+
81+
Sqlserver::User::Permissions{
82+
user => $user,
83+
database => $database,
84+
instance => $instance,
85+
require => Sqlserver_tsql["user-${instance}-${database}-${user}"]
86+
}
87+
if has_key($_upermissions, 'GRANT') and is_array($_upermissions['GRANT']) {
88+
sqlserver::user::permissions{ "Sqlserver::User[${title}]-GRANT-${user}":
89+
state => 'GRANT',
90+
permissions => $_upermissions['GRANT'],
91+
}
92+
}
93+
if has_key($_upermissions, 'DENY') and is_array($_upermissions['DENY']) {
94+
sqlserver::user::permissions{ "Sqlserver::User[${title}]-DENY-${user}":
95+
state => 'DENY',
96+
permissions => $_upermissions['DENY'],
97+
}
98+
}
99+
if has_key($_upermissions, 'REVOKE') and is_array($_upermissions['REVOKE']) {
100+
sqlserver::user::permissions{ "Sqlserver::User[${title}]-REVOKE-${user}":
101+
state => 'REVOKE',
102+
permissions => $_upermissions['REVOKE'],
103+
}
104+
}
105+
if has_key($_upermissions, 'GRANT_WITH_OPTION') and is_array($_upermissions['GRANT_WITH_OPTION']) {
106+
sqlserver::user::permissions{ "Sqlserver::User[${title}]-GRANT-WITH_GRANT_OPTION-${user}":
107+
state => 'GRANT',
108+
with_grant_option => true,
109+
permissions => $_upermissions['GRANT_WITH_OPTION'],
110+
}
111+
}
112+
}
72113
}

manifests/user/permission.pp renamed to manifests/user/permissions.pp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
##
2-
# == Define Resource Type: sqlserver::user::permission#
2+
# == Define Resource Type: sqlserver::user::permissions
33
#
44
# === Requirement/Dependencies:
55
#
@@ -26,7 +26,7 @@
2626
# The name of the instance where the user and database exists. Defaults to 'MSSQLSERVER'
2727
#
2828
##
29-
define sqlserver::user::permission (
29+
define sqlserver::user::permissions (
3030
$user,
3131
$database,
3232
$permissions,

spec/defines/login/permission_spec.rb renamed to spec/defines/login/permissions_spec.rb

+22-22
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
require 'spec_helper'
22
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'manifest_shared_examples.rb'))
33

4-
describe 'sqlserver::login::permission' do
4+
describe 'sqlserver::login::permissions' do
55
let(:facts) { {:osfamily => 'windows'} }
66
context 'validation errors' do
77
include_context 'manifests' do
@@ -10,11 +10,11 @@
1010
end
1111
context 'login =>' do
1212
let(:params) { {
13-
:permissions=> ['SELECT'],
13+
:permissions => ['SELECT'],
1414
} }
1515
let(:raise_error_check) { 'Login must be between 1 and 128 characters' }
1616
describe 'missing' do
17-
let(:raise_error_check) { 'Must pass login to Sqlserver::Login::Permission[myTitle]' }
17+
let(:raise_error_check) { 'Must pass login to Sqlserver::Login::Permissions[myTitle]' }
1818
it_behaves_like 'validation error'
1919
end
2020
describe 'empty' do
@@ -28,26 +28,26 @@
2828
end
2929
context 'permission' do
3030
let(:params) { {
31-
:login => 'loggingUser',
31+
:login => 'loggingUser',
3232
} }
3333
let(:raise_error_check) { 'Permission must be between 4 and 128 characters' }
3434
describe 'empty' do
35-
let(:additional_params) { {:permissions=> ['']} }
35+
let(:additional_params) { {:permissions => ['']} }
3636
it_behaves_like 'validation error'
3737
end
3838
describe 'under limit' do
39-
let(:additional_params) { {:permissions=> [random_string_of_size(3, false)]} }
39+
let(:additional_params) { {:permissions => [random_string_of_size(3, false)]} }
4040
it_behaves_like 'validation error'
4141
end
4242
describe 'over limit' do
43-
let(:additional_params) { {:permissions=> [random_string_of_size(129, false)]} }
43+
let(:additional_params) { {:permissions => [random_string_of_size(129, false)]} }
4444
it_behaves_like 'validation error'
4545
end
4646
end
4747
context 'state =>' do
4848
let(:params) { {
49-
:permissions=> ['SELECT'],
50-
:login => 'loggingUser'
49+
:permissions => ['SELECT'],
50+
:login => 'loggingUser'
5151
} }
5252
describe 'invalid' do
5353
let(:additional_params) { {:state => 'invalid'} }
@@ -61,8 +61,8 @@
6161
let(:title) { 'myTitle' }
6262
let(:sqlserver_tsql_title) { 'login-permission-MSSQLSERVER-loggingUser-GRANT' }
6363
let(:params) { {
64-
:login => 'loggingUser',
65-
:permissions=> ['SELECT'],
64+
:login => 'loggingUser',
65+
:permissions => ['SELECT'],
6666
} }
6767
end
6868
%w(revoke grant deny).each do |state|
@@ -90,7 +90,7 @@
9090
it_behaves_like 'sqlserver_tsql command'
9191
end
9292
describe 'alter' do
93-
let(:additional_params) { {:permissions=> ['ALTER']} }
93+
let(:additional_params) { {:permissions => ['ALTER']} }
9494
let(:should_contain_command) { ['USE [master];', 'GRANT ALTER TO [loggingUser];'] }
9595
let(:sqlserver_tsql_title) { "login-permission-MSSQLSERVER-loggingUser-GRANT" }
9696
it_behaves_like 'sqlserver_tsql command'
@@ -113,19 +113,19 @@
113113
let(:title) { 'myTitle' }
114114
let(:sqlserver_tsql_title) { 'login-permission-MSSQLSERVER-loggingUser-GRANT' }
115115
let(:params) { {
116-
:login => 'loggingUser',
117-
:permissions => ['SELECT'],
116+
:login => 'loggingUser',
117+
:permissions => ['SELECT'],
118118
} }
119119
describe '' do
120120
let(:should_contain_command) { [
121-
'USE [master];',
122-
'GRANT SELECT TO [loggingUser];',
123-
/DECLARE @perm_state varchar\(250\)/,
124-
/SET @perm_state = ISNULL\(\n\s+\(SELECT perm.state_desc FROM sys\.server_permissions perm\n\s+JOIN sys\./,
125-
/JOIN sys\.server_principals princ ON princ.principal_id = perm\.grantee_principal_id\n\s+WHERE/,
126-
/WHERE princ\.type IN \('U','S','G'\)\n\s+ AND princ\.name = 'loggingUser'\n\s+AND perm\.permission_name = @permission\),\n\s+'REVOKE'\)/,
127-
/SET @error_msg = 'EXPECTED login \[loggingUser\] to have permission \[' \+ @permission \+ '\] with GRANT but got ' \+ @perm_state;/,
128-
/IF @perm_state != 'GRANT'\n\s+THROW 51000, @error_msg, 10/
121+
'USE [master];',
122+
'GRANT SELECT TO [loggingUser];',
123+
/DECLARE @perm_state varchar\(250\)/,
124+
/SET @perm_state = ISNULL\(\n\s+\(SELECT perm.state_desc FROM sys\.server_permissions perm\n\s+JOIN sys\./,
125+
/JOIN sys\.server_principals princ ON princ.principal_id = perm\.grantee_principal_id\n\s+WHERE/,
126+
/WHERE princ\.type IN \('U','S','G'\)\n\s+ AND princ\.name = 'loggingUser'\n\s+AND perm\.permission_name = @permission\),\n\s+'REVOKE'\)/,
127+
/SET @error_msg = 'EXPECTED login \[loggingUser\] to have permission \[' \+ @permission \+ '\] with GRANT but got ' \+ @perm_state;/,
128+
/IF @perm_state != 'GRANT'\n\s+THROW 51000, @error_msg, 10/
129129
] }
130130
it_behaves_like 'sqlserver_tsql command'
131131
end

0 commit comments

Comments
 (0)