Skip to content

Commit 461ba1b

Browse files
author
Travis Fields
committed
FM-2236 Add with_grant_option for user permission
1 parent 5249370 commit 461ba1b

File tree

7 files changed

+92
-32
lines changed

7 files changed

+92
-32
lines changed

manifests/user/permission.pp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,20 @@
1919
# [state]
2020
# The state you would like the permission in. Accepts 'GRANT', 'DENY', 'REVOKE' Please note that REVOKE equates to absent and will default to database and system level permissions.
2121
#
22+
# [with_grant_option]
23+
# Whether to give the user the option to grant this permission to other users, accepts true or false, defaults to false
24+
#
2225
# [instance]
2326
# The name of the instance where the user and database exists. Defaults to 'MSSQLSERVER'
2427
#
2528
##
2629
define sqlserver::user::permission (
2730
$user,
2831
$database,
29-
$permission = $title,
30-
$state = 'GRANT',
31-
$instance = 'MSSQLSERVER',
32+
$permission = $title,
33+
$state = 'GRANT',
34+
$with_grant_option = false,
35+
$instance = 'MSSQLSERVER',
3236
){
3337
sqlserver_validate_instance_name($instance)
3438

@@ -41,16 +45,20 @@
4145
$_state = upcase($state)
4246
validate_re($_state,'^(GRANT|REVOKE|DENY)$',"State can only be of 'GRANT', 'REVOKE' or 'DENY' you passed ${state}")
4347

48+
validate_bool($with_grant_option)
49+
if $with_grant_option and $_state != 'GRANT' {
50+
fail("Can not use with_grant_option and state ${_state}, must be 'GRANT'")
51+
}
52+
4453
sqlserver_validate_range($database, 1, 128, 'Database must be between 1 and 128 characters')
4554

4655
sqlserver_validate_range($user, 1, 128, 'User must be between 1 and 128 characters')
4756

4857
sqlserver_tsql{
49-
"user-permissions-${instance}-${database}-${user}-${$_state}-${_permission}":
58+
"user-permissions-${instance}-${database}-${user}-${_permission}":
5059
instance => $instance,
51-
command => template("sqlserver/create/user_permission.sql.erb"),
52-
onlyif => template('sqlserver/query/user_permission_exists.sql.erb'),
60+
command => template("sqlserver/create/user/permission.sql.erb"),
61+
onlyif => template('sqlserver/query/user/permission_exists.sql.erb'),
5362
require => Sqlserver::Config[$instance],
5463
}
55-
5664
}

spec/defines/user/permission_spec.rb

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
context 'validation errors' do
77
include_context 'manifests' do
88
let(:title) { 'myTitle' }
9-
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' }
9+
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-SELECT' }
1010
end
1111
context 'user =>' do
1212
let(:params) { {
@@ -24,6 +24,7 @@
2424
end
2525
describe 'over limit' do
2626
let(:additional_params) { {:user => random_string_of_size(129)} }
27+
it_behaves_like 'validation error'
2728
end
2829
end
2930
context 'permission' do
@@ -57,11 +58,29 @@
5758
it_behaves_like 'validation error'
5859
end
5960
end
61+
context 'with_grant_option => ' do
62+
let(:params) { {
63+
:permission => 'SELECT',
64+
:database => 'loggingDb',
65+
:user => 'loggingUser',
66+
67+
} }
68+
describe 'true AND state => DENY' do
69+
let(:additional_params) { {:with_grant_option => true, :state => 'DENY'} }
70+
let(:raise_error_check) { "Can not use with_grant_option and state DENY, must be 'GRANT' " }
71+
it_behaves_like 'validation error'
72+
end
73+
describe 'invalid' do
74+
let(:additional_params) { {:with_grant_option => 'invalid'} }
75+
let(:raise_error_check) { '"invalid" is not a boolean' }
76+
it_behaves_like 'validation error'
77+
end
78+
end
6079
end
6180
context 'successfully' do
6281
include_context 'manifests' do
6382
let(:title) { 'myTitle' }
64-
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' }
83+
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-SELECT' }
6584
let(:params) { {
6685
:user => 'loggingUser',
6786
:permission => 'SELECT',
@@ -70,7 +89,7 @@
7089
end
7190
%w(revoke grant deny).each do |state|
7291
context "state => '#{state}'" do
73-
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-#{state.upcase}-SELECT" }
92+
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-SELECT' }
7493
let(:should_contain_command) { ["#{state.upcase} SELECT TO [loggingUser];", 'USE [loggingDb];'] }
7594
describe "lowercase #{state}" do
7695
let(:additional_params) { {:state => state} }
@@ -88,14 +107,14 @@
88107
describe 'upper limit' do
89108
permission =random_string_of_size(128, false)
90109
let(:additional_params) { {:permission => permission} }
91-
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-#{permission.upcase}" }
110+
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-#{permission.upcase}" }
92111
let(:should_contain_command) { ['USE [loggingDb];'] }
93112
it_behaves_like 'sqlserver_tsql command'
94113
end
95114
describe 'alter' do
96115
let(:additional_params) { {:permission => 'ALTER'} }
97116
let(:should_contain_command) { ['USE [loggingDb];', 'GRANT ALTER TO [loggingUser];'] }
98-
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-ALTER" }
117+
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-ALTER' }
99118
it_behaves_like 'sqlserver_tsql command'
100119
end
101120
end
@@ -110,12 +129,39 @@
110129
it_behaves_like 'compile'
111130
end
112131

132+
context 'with_grant_option =>' do
133+
describe 'true' do
134+
let(:additional_params) { {:with_grant_option => true} }
135+
let(:should_contain_command) { [
136+
"IF @perm_state != 'GRANT_WITH_GRANT_OPTION'",
137+
'GRANT SELECT TO [loggingUser] WITH GRANT OPTION;',
138+
] }
139+
let(:should_not_contain_command) { [
140+
'REVOKE GRANT OPTION FOR SELECT FROM [loggingUser];'] }
141+
let(:should_contain_onlyif) { ["IF @perm_state != 'GRANT_WITH_GRANT_OPTION'",] }
142+
it_behaves_like 'sqlserver_tsql command'
143+
it_behaves_like 'sqlserver_tsql without_command'
144+
it_behaves_like 'sqlserver_tsql onlyif'
145+
end
146+
describe 'false' do
147+
let(:should_contain_command) { [
148+
"IF @perm_state != 'GRANT'",
149+
'GRANT SELECT TO [loggingUser];',
150+
'REVOKE GRANT OPTION FOR SELECT TO [loggingUser] CASCADE;',
151+
"IF 'GRANT_WITH_GRANT_OPTION' = ISNULL(",
152+
] }
153+
154+
let(:should_contain_onlyif) { ["IF @perm_state != 'GRANT'",] }
155+
it_behaves_like 'sqlserver_tsql command'
156+
it_behaves_like 'sqlserver_tsql onlyif'
157+
end
158+
end
113159
end
114160

115161
context 'command syntax' do
116162
include_context 'manifests' do
117163
let(:title) { 'myTitle' }
118-
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' }
164+
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-SELECT' }
119165
let(:params) { {
120166
:user => 'loggingUser',
121167
:permission => 'SELECT',
@@ -128,7 +174,7 @@
128174
/DECLARE @perm_state varchar\(250\)/,
129175
/SET @perm_state = ISNULL\(\n\s+\(SELECT perm.state_desc FROM sys\.database_principals princ\n\s+JOIN sys\./,
130176
/JOIN sys\.database_permissions perm ON perm\.grantee_principal_id = princ.principal_id\n\s+WHERE/,
131-
/WHERE princ\.type in \('U','S','G'\) AND name = 'loggingUser' AND permission_name = 'SELECT' \),\n\s+'REVOKE'\);/,
177+
/WHERE princ\.type in \('U','S','G'\) AND name = 'loggingUser' AND permission_name = 'SELECT'\),\n\s+'REVOKE'\)\s+;/,
132178
/DECLARE @error_msg varchar\(250\);\nSET @error_msg = 'EXPECTED user \[loggingUser\] to have permission \[SELECT\] with GRANT but got ' \+ @perm_state;/,
133179
/IF @perm_state != 'GRANT'\n\s+THROW 51000, @error_msg, 10/
134180
] }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
BEGIN
2+
USE [<%= @database %>];
3+
<% if @with_grant_option == false %>
4+
IF 'GRANT_WITH_GRANT_OPTION' = <%= scope.function_template(['sqlserver/snippets/user/permission/get_perm_state.sql.erb']) %>
5+
REVOKE GRANT OPTION FOR <%= @_permission %> TO [<%= @user %>] CASCADE;
6+
<% end %>
7+
<%= @_state %> <%= @_permission %> TO [<%= @user %>]<% if @with_grant_option == true %> WITH GRANT OPTION<% end %>;
8+
END
9+
BEGIN
10+
<%= scope.function_template(['sqlserver/query/user/permission_exists.sql.erb']) %>
11+
END

templates/create/user_permission.sql.erb

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
USE [<%= @database %>];
2+
DECLARE @perm_state varchar(250);
3+
SET @perm_state = <%= scope.function_template(['sqlserver/snippets/user/permission/get_perm_state.sql.erb']) %>;
4+
DECLARE @error_msg varchar(250);
5+
SET @error_msg = 'EXPECTED user [<%= @user %>] to have permission [<%= @_permission %>] with <%= @_state %> but got ' + @perm_state;
6+
7+
IF @perm_state != '<% if @with_grant_option == true %>GRANT_WITH_GRANT_OPTION<% else %><%= @_state %><% end %>'
8+
THROW 51000, @error_msg, 10

templates/query/user_permission_exists.sql.erb

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ISNULL(
2+
(SELECT perm.state_desc FROM sys.database_principals princ
3+
JOIN sys.database_permissions perm ON perm.grantee_principal_id = princ.principal_id
4+
WHERE princ.type in ('U','S','G') AND name = '<%= @user %>' AND permission_name = '<%= @_permission %>'),
5+
'REVOKE')

0 commit comments

Comments
 (0)