Skip to content

Commit dc0a5a0

Browse files
committed
Merge pull request #70 from cyberious/FM-2246
FM-1898 Add sqlserver::user::permssion with GRANT, REVOKE and DENY
2 parents 675f974 + b80ce9e commit dc0a5a0

11 files changed

+259
-20
lines changed

.fixtures.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
fixtures:
22
forge_modules:
33
stdlib: "puppetlabs/stdlib"
4+
acl: "puppetlabs/acl"
45
symlinks:
5-
"sqlserver": "#{source_dir}"
6+
sqlserver: "#{source_dir}"

.geppetto-rc.json

-9
This file was deleted.

Gemfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ group :development, :test do
44
gem 'nokogiri'
55
gem 'mime-types', '<2.0', :require => false
66
gem 'rake', :require => false
7-
gem 'rspec-puppet', '~>1.0', :require => false
7+
gem 'rspec-puppet', '~>2.0', :require => false
88
gem 'puppetlabs_spec_helper', :require => false
99
gem 'puppet-lint', :require => false
1010
gem 'simplecov', :require => false
11-
gem 'rspec', '~> 2.14.0', :require => false
11+
gem 'rspec', :require => false
1212
gem 'beaker-rspec', :require => false
1313
gem 'yard', :require => false
1414
gem 'pry', :require => false

manifests/user/permission.pp

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
##
2+
# == Define Resource Type: sqlserver::user::permission#
3+
#
4+
# === Requirement/Dependencies:
5+
#
6+
# Requires defined type {sqlserver::config} in order to execute against the SQL Server instance
7+
#
8+
#
9+
# === Parameters
10+
# [user]
11+
# The username for which the permission will be manage.
12+
#
13+
# [database]
14+
# The databaser you would like the permission managed on.
15+
#
16+
# [permission]
17+
# The permission you would like managed. i.e. 'SELECT', 'INSERT', 'UPDATE', 'DELETE'
18+
#
19+
# [state]
20+
# 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.
21+
#
22+
# [instance]
23+
# The name of the instance where the user and database exists. Defaults to 'MSSQLSERVER'
24+
#
25+
##
26+
define sqlserver::user::permission (
27+
$user,
28+
$database,
29+
$permission = $title,
30+
$state = 'GRANT',
31+
$instance = 'MSSQLSERVER',
32+
){
33+
sqlserver_validate_instance_name($instance)
34+
35+
## Validate Permissions
36+
$_permission = upcase($permission)
37+
sqlserver_validate_range($_permission, 4, 128, 'Permission must be between 4 and 128 characters')
38+
validate_re($_permission, '^([A-Z]|\s)+$','Permissions must be alphabetic only')
39+
40+
## Validate state
41+
$_state = upcase($state)
42+
validate_re($_state,'^(GRANT|REVOKE|DENY)$',"State can only be of 'GRANT', 'REVOKE' or 'DENY' you passed ${state}")
43+
44+
sqlserver_validate_range($database, 1, 128, 'Database must be between 1 and 128 characters')
45+
46+
sqlserver_validate_range($user, 1, 128, 'User must be between 1 and 128 characters')
47+
48+
sqlserver_tsql{
49+
"user-permissions-${instance}-${database}-${user}-${$_state}-${_permission}":
50+
instance => $instance,
51+
command => template("sqlserver/create/user_permission.sql.erb"),
52+
onlyif => template('sqlserver/query/user_permission_exists.sql.erb'),
53+
require => Sqlserver::Config[$instance],
54+
}
55+
56+
}

spec/defines/config_spec.rb

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
require 'spec_helper'
2+
require File.expand_path(File.join(File.dirname(__FILE__), 'manifest_shared_examples.rb'))
3+
4+
RSpec.describe 'sqlserver::config', :type => :define do
5+
let(:title) { 'MSSQLSERVER' }
6+
let(:params) { {
7+
:instance_name => 'MSSQLSERVER',
8+
:admin_user => 'sa',
9+
:admin_pass => 'Pupp3t1@',
10+
} }
11+
let(:facts) { {:osfamily => 'windows', :platform => :windows} }
12+
describe 'compile' do
13+
it {
14+
should contain_file('C:/Program Files/Microsoft SQL Server/.puppet/.MSSQLSERVER.cfg')
15+
should contain_file('C:/Program Files/Microsoft SQL Server/.puppet')
16+
}
17+
end
18+
end

spec/defines/database_spec.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@
1212
end
1313

1414
describe 'Minimal Params' do
15-
it_behaves_like 'sqlserver_tsql command'
15+
let(:pre_condition) { <<-EOF
16+
define sqlserver::config{}
17+
sqlserver::config {'MSSQLSERVER': }
18+
EOF
19+
}
20+
it_behaves_like 'compile'
1621
end
1722

1823
describe 'Providing log filespec it should compile with valid log on params and' do

spec/defines/manifest_shared_examples.rb

+11-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def convert_to_regexp(str)
4242
}
4343

4444
end
45+
4546
shared_examples 'sqlserver_tsql without_command' do
4647
it {
4748
params.merge!(additional_params)
@@ -50,16 +51,25 @@ def convert_to_regexp(str)
5051
end
5152
}
5253
end
54+
5355
shared_examples 'compile' do
5456
it {
5557
params.merge!(additional_params)
5658
should compile
5759
}
5860
end
61+
5962
shared_examples 'validation error' do
6063
it {
6164
params.merge!(additional_params)
62-
expect { should compile }.to raise_error(error_class, convert_to_regexp(raise_error_check))
65+
expect { should contain_sqlserver_tsql(sqlserver_tsql_title) }.to raise_error(error_class, convert_to_regexp(raise_error_check))
6366
}
6467
end
6568
end
69+
70+
def random_string_of_size(size, include_numeric = true)
71+
pool = [('a'..'z'), ('A'..'Z')]
72+
pool << (0..9) if include_numeric
73+
o = pool.map { |i| i.to_a }.flatten
74+
(0...size).map { o[rand(o.length)] }.join
75+
end

spec/defines/user/permission_spec.rb

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
require 'spec_helper'
2+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'manifest_shared_examples.rb'))
3+
4+
describe 'sqlserver::user::permission' do
5+
let(:facts) { {:osfamily => 'windows'} }
6+
context 'validation errors' do
7+
include_context 'manifests' do
8+
let(:title) { 'myTitle' }
9+
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' }
10+
end
11+
context 'user =>' do
12+
let(:params) { {
13+
:permission => 'SELECT',
14+
:database => 'loggingDb',
15+
} }
16+
let(:raise_error_check) { 'User must be between 1 and 128 characters' }
17+
describe 'missing' do
18+
let(:raise_error_check) { 'Must pass user to Sqlserver::User::Permission[myTitle]' }
19+
it_behaves_like 'validation error'
20+
end
21+
describe 'empty' do
22+
let(:additional_params) { {:user => ''} }
23+
it_behaves_like 'validation error'
24+
end
25+
describe 'over limit' do
26+
let(:additional_params) { {:user => random_string_of_size(129)} }
27+
end
28+
end
29+
context 'permission' do
30+
let(:params) { {
31+
:user => 'loggingUser',
32+
:database => 'loggingDb',
33+
} }
34+
let(:raise_error_check) { 'Permission must be between 4 and 128 characters' }
35+
describe 'empty' do
36+
let(:additional_params) { {:permission => ''} }
37+
it_behaves_like 'validation error'
38+
end
39+
describe 'under limit' do
40+
let(:additional_params) { {:permission => random_string_of_size(3, false)} }
41+
it_behaves_like 'validation error'
42+
end
43+
describe 'over limit' do
44+
let(:additional_params) { {:permission => random_string_of_size(129, false)} }
45+
it_behaves_like 'validation error'
46+
end
47+
end
48+
context 'state =>' do
49+
let(:params) { {
50+
:permission => 'SELECT',
51+
:database => 'loggingDb',
52+
:user => 'loggingUser'
53+
} }
54+
describe 'invalid' do
55+
let(:additional_params) { {:state => 'invalide'} }
56+
let(:raise_error_check) { "State can only be of 'GRANT', 'REVOKE' or 'DENY' you passed invalide" }
57+
it_behaves_like 'validation error'
58+
end
59+
end
60+
end
61+
context 'successfully' do
62+
include_context 'manifests' do
63+
let(:title) { 'myTitle' }
64+
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' }
65+
let(:params) { {
66+
:user => 'loggingUser',
67+
:permission => 'SELECT',
68+
:database => 'loggingDb',
69+
} }
70+
end
71+
%w(revoke grant deny).each do |state|
72+
context "state => '#{state}'" do
73+
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-#{state.upcase}-SELECT" }
74+
let(:should_contain_command) { ["#{state.upcase} SELECT TO [loggingUser];", 'USE [loggingDb];'] }
75+
describe "lowercase #{state}" do
76+
let(:additional_params) { {:state => state} }
77+
it_behaves_like 'sqlserver_tsql command'
78+
end
79+
state.capitalize!
80+
describe "capitalized #{state}" do
81+
let(:additional_params) { {:state => state} }
82+
it_behaves_like 'sqlserver_tsql command'
83+
end
84+
end
85+
end
86+
87+
context 'permission' do
88+
describe 'upper limit' do
89+
permission =random_string_of_size(128, false)
90+
let(:additional_params) { {:permission => permission} }
91+
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-#{permission.upcase}" }
92+
let(:should_contain_command) { ['USE [loggingDb];'] }
93+
it_behaves_like 'sqlserver_tsql command'
94+
end
95+
describe 'alter' do
96+
let(:additional_params) { {:permission => 'ALTER'} }
97+
let(:should_contain_command) { ['USE [loggingDb];', 'GRANT ALTER TO [loggingUser];'] }
98+
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-ALTER" }
99+
it_behaves_like 'sqlserver_tsql command'
100+
end
101+
end
102+
103+
describe 'Minimal Params' do
104+
let(:pre_condition) { <<-EOF
105+
define sqlserver::config{}
106+
sqlserver::config {'MSSQLSERVER': }
107+
EOF
108+
}
109+
let(:should_contain_command) { ['USE [loggingDb];'] }
110+
it_behaves_like 'compile'
111+
end
112+
113+
end
114+
115+
context 'command syntax' do
116+
include_context 'manifests' do
117+
let(:title) { 'myTitle' }
118+
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' }
119+
let(:params) { {
120+
:user => 'loggingUser',
121+
:permission => 'SELECT',
122+
:database => 'loggingDb',
123+
} }
124+
describe '' do
125+
let(:should_contain_command) { [
126+
'USE [loggingDb];',
127+
'GRANT SELECT TO [loggingUser];',
128+
/DECLARE @perm_state varchar\(250\)/,
129+
/SET @perm_state = ISNULL\(\n\s+\(SELECT perm.state_desc FROM sys\.database_principals princ\n\s+JOIN sys\./,
130+
/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'\);/,
132+
/DECLARE @error_msg varchar\(250\);\nSET @error_msg = 'EXPECTED user \[loggingUser\] to have permission \[SELECT\] with GRANT but got ' \+ @perm_state;/,
133+
/IF @perm_state != 'GRANT'\n\s+THROW 51000, @error_msg, 10/
134+
] }
135+
it_behaves_like 'sqlserver_tsql command'
136+
end
137+
end
138+
end
139+
140+
end

spec/spec_helper.rb

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
require 'simplecov'
2-
require 'rspec'
3-
2+
require 'rspec-puppet'
43
require 'puppetlabs_spec_helper/module_spec_helper'
54

6-
dir = File.expand_path(File.dirname(__FILE__))
7-
$LOAD_PATH.unshift File.join(dir, 'lib')
8-
module PuppetSpec
9-
FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR)
5+
fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))
6+
7+
RSpec.configure do |c|
8+
c.module_path = File.join(fixture_path, 'modules')
9+
c.manifest_dir = File.join(fixture_path, 'manifests')
1010
end
1111

1212
SimpleCov.start do
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
BEGIN
2+
USE [<%= @database %>];
3+
<%= @_state %> <%= @_permission %> TO [<%= @user %>];
4+
END
5+
BEGIN
6+
<%= scope.function_template(['sqlserver/query/user_permission_exists.sql.erb']) %>
7+
END
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
USE [<%= @database %>];
2+
DECLARE @perm_state varchar(250);
3+
SET @perm_state = ISNULL(
4+
(SELECT perm.state_desc FROM sys.database_principals princ
5+
JOIN sys.database_permissions perm ON perm.grantee_principal_id = princ.principal_id
6+
WHERE princ.type in ('U','S','G') AND name = '<%= @user %>' AND permission_name = '<%= @_permission %>' ),
7+
'REVOKE');
8+
DECLARE @error_msg varchar(250);
9+
SET @error_msg = 'EXPECTED user [<%= @user %>] to have permission [<%= @_permission %>] with <%= @_state %> but got ' + @perm_state;
10+
IF @perm_state != '<%= @_state %>'
11+
THROW 51000, @error_msg, 10

0 commit comments

Comments
 (0)