Skip to content

Commit 7130984

Browse files
author
Travis Fields
committed
FM-2299 Login - Allow for permissions hash
1 parent 23faa7c commit 7130984

File tree

4 files changed

+154
-39
lines changed

4 files changed

+154
-39
lines changed

manifests/login.pp

Lines changed: 44 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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',

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

Lines changed: 22 additions & 22 deletions
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

spec/defines/login_spec.rb

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
let(:sqlserver_tsql_title) { 'login-MSSQLSERVER-myTitle' }
77
let(:title) { 'myTitle' }
88
let(:params) { {
9-
:login => 'myTitle',
10-
:instance => 'MSSQLSERVER',
9+
:login => 'myTitle',
10+
:instance => 'MSSQLSERVER',
1111
} }
1212
end
1313

@@ -18,19 +18,19 @@
1818
end
1919
describe 'parameter assignment' do
2020
let(:should_contain_command) { [
21-
"IF exists(select * from sys.sql_logins where name = 'myTitle')",
22-
"@login as varchar(255) = 'myTitle'",
23-
'@is_disabled as tinyint = 0'
21+
"IF exists(select * from sys.sql_logins where name = 'myTitle')",
22+
"@login as varchar(255) = 'myTitle'",
23+
'@is_disabled as tinyint = 0'
2424
] }
2525
let(:should_contain_onlyif) { [
26-
"@login as varchar(255) = 'myTitle'",
27-
"@is_disabled as tinyint = 0",
28-
"@check_expiration as tinyint = 0",
29-
"@check_policy as tinyint = 1",
30-
"@type_desc as varchar(50) = 'SQL_LOGIN'",
31-
"@default_db as varchar(255) = 'master'",
32-
"@default_lang as varchar(50) = 'us_english'",
33-
"IF NOT EXISTS(SELECT name FROM sys.server_principals WHERE name = 'myTitle')"
26+
"@login as varchar(255) = 'myTitle'",
27+
"@is_disabled as tinyint = 0",
28+
"@check_expiration as tinyint = 0",
29+
"@check_policy as tinyint = 1",
30+
"@type_desc as varchar(50) = 'SQL_LOGIN'",
31+
"@default_db as varchar(255) = 'master'",
32+
"@default_lang as varchar(50) = 'us_english'",
33+
"IF NOT EXISTS(SELECT name FROM sys.server_principals WHERE name = 'myTitle')"
3434
] }
3535
it_behaves_like 'sqlserver_tsql command'
3636
it_behaves_like 'sqlserver_tsql onlyif'
@@ -40,4 +40,77 @@
4040
let(:raise_error_check) { 'Can not have check expiration enabled when check_policy is disabled' }
4141
it_should_behave_like 'validation error'
4242
end
43+
context 'permissions =>' do
44+
let(:title) { 'myTitle' }
45+
let(:params) { {
46+
:login => 'myLogin',
47+
} }
48+
let(:permissions) { {} }
49+
shared_examples 'sqlserver_permissions exists' do |type|
50+
it {
51+
params[:permissions] = permissions
52+
type_title = (type =~ /GRANT_WITH_OPTION/i ? 'GRANT-WITH_GRANT_OPTION' : type.upcase)
53+
should contain_sqlserver__login__permissions("Sqlserver::Login[#{title}]-#{type_title}-myLogin").with(
54+
{
55+
'login' => 'myLogin',
56+
'state' => type == 'GRANT_WITH_OPTION' ? 'GRANT' : type.upcase,
57+
'with_grant_option' => type == 'GRANT_WITH_OPTION',
58+
'permissions' => permissions[type],
59+
'require' => 'Sqlserver_tsql[login-MSSQLSERVER-myLogin]'
60+
}
61+
)
62+
}
63+
end
64+
65+
shared_examples 'sqlserver_permissions absent' do |type|
66+
it {
67+
params[:permissions] = permissions
68+
type_title = (type =~ /GRANT_WITH_OPTION/i ? 'GRANT-WITH_GRANT_OPTION' : type.upcase)
69+
should_not contain_sqlserver__login__permissions("Sqlserver::Login[#{title}]-#{type_title}-myLogin")
70+
}
71+
end
72+
73+
describe 'GRANT permissions' do
74+
let(:permissions) { {'GRANT' => ['SELECT']} }
75+
it_behaves_like 'sqlserver_permissions exists', 'GRANT'
76+
it_behaves_like 'sqlserver_permissions absent', 'DENY'
77+
it_behaves_like 'sqlserver_permissions absent', 'REVOKE'
78+
it_behaves_like 'sqlserver_permissions absent', 'GRANT_WITH_OPTION'
79+
end
80+
81+
describe 'GRANT DENY' do
82+
let(:permissions) { {'GRANT' => ['CONNECT SQL'], 'DENY' => ['INSERT']} }
83+
it_behaves_like 'sqlserver_permissions exists', 'GRANT'
84+
it_behaves_like 'sqlserver_permissions exists', 'DENY'
85+
it_behaves_like 'sqlserver_permissions absent', 'REVOKE'
86+
it_behaves_like 'sqlserver_permissions absent', 'GRANT_WITH_OPTION'
87+
end
88+
89+
describe 'GRANT_WITH_OPTION' do
90+
let(:permissions) { {'GRANT_WITH_OPTION' => ['CONNECT SQL']} }
91+
it_behaves_like 'sqlserver_permissions exists', 'GRANT_WITH_OPTION'
92+
end
93+
94+
describe 'REVOKE' do
95+
let(:permissions) { {'revoke' => ['CREATE ANY DATABASE']} }
96+
it_behaves_like 'sqlserver_permissions exists', 'revoke'
97+
it_behaves_like 'sqlserver_permissions absent', 'GRANT'
98+
it_behaves_like 'sqlserver_permissions absent', 'DENY'
99+
it_behaves_like 'sqlserver_permissions absent', 'GRANT_WITH_OPTION'
100+
end
101+
102+
describe 'empty' do
103+
%w(GRANT DENY REVOKE GRANT-WITH_GRANT_OPTION).each do |type|
104+
it_behaves_like 'sqlserver_permissions absent', type
105+
end
106+
end
107+
108+
describe 'duplicate permissions' do
109+
let(:additional_params) { {
110+
:permissions => {'GRANT' => ['CONNECT SQL'], 'REVOKE' => ['CONNECT SQL']}
111+
} }
112+
let(:raise_error_check) { "Duplicate permissions found for sqlserver::login[#{title}" }
113+
it_behaves_like 'validation error'
114+
end
115+
end
43116
end

0 commit comments

Comments
 (0)