-
Notifications
You must be signed in to change notification settings - Fork 21
FM-1898 Add sqlserver::user::permssion with GRANT, REVOKE and DENY #70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
fixtures: | ||
forge_modules: | ||
stdlib: "puppetlabs/stdlib" | ||
acl: "puppetlabs/acl" | ||
symlinks: | ||
"sqlserver": "#{source_dir}" | ||
sqlserver: "#{source_dir}" |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
## | ||
# == Define Resource Type: sqlserver::user::permission# | ||
# | ||
# === Requirement/Dependencies: | ||
# | ||
# Requires defined type {sqlserver::config} in order to execute against the SQL Server instance | ||
# | ||
# | ||
# === Parameters | ||
# [user] | ||
# The username for which the permission will be manage. | ||
# | ||
# [database] | ||
# The databaser you would like the permission managed on. | ||
# | ||
# [permission] | ||
# The permission you would like managed. i.e. 'SELECT', 'INSERT', 'UPDATE', 'DELETE' | ||
# | ||
# [state] | ||
# 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. | ||
# | ||
# [instance] | ||
# The name of the instance where the user and database exists. Defaults to 'MSSQLSERVER' | ||
# | ||
## | ||
define sqlserver::user::permission ( | ||
$user, | ||
$database, | ||
$permission = $title, | ||
$state = 'GRANT', | ||
$instance = 'MSSQLSERVER', | ||
){ | ||
sqlserver_validate_instance_name($instance) | ||
|
||
## Validate Permissions | ||
$_permission = upcase($permission) | ||
sqlserver_validate_range($_permission, 4, 128, 'Permission must be between 4 and 128 characters') | ||
validate_re($_permission, '^([A-Z]|\s)+$','Permissions must be alphabetic only') | ||
|
||
## Validate state | ||
$_state = upcase($state) | ||
validate_re($_state,'^(GRANT|REVOKE|DENY)$',"State can only be of 'GRANT', 'REVOKE' or 'DENY' you passed ${state}") | ||
|
||
sqlserver_validate_range($database, 1, 128, 'Database must be between 1 and 128 characters') | ||
|
||
sqlserver_validate_range($user, 1, 128, 'User must be between 1 and 128 characters') | ||
|
||
sqlserver_tsql{ | ||
"user-permissions-${instance}-${database}-${user}-${$_state}-${_permission}": | ||
instance => $instance, | ||
command => template("sqlserver/create/user_permission.sql.erb"), | ||
onlyif => template('sqlserver/query/user_permission_exists.sql.erb'), | ||
require => Sqlserver::Config[$instance], | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
require 'spec_helper' | ||
require File.expand_path(File.join(File.dirname(__FILE__), 'manifest_shared_examples.rb')) | ||
|
||
RSpec.describe 'sqlserver::config', :type => :define do | ||
let(:title) { 'MSSQLSERVER' } | ||
let(:params) { { | ||
:instance_name => 'MSSQLSERVER', | ||
:admin_user => 'sa', | ||
:admin_pass => 'Pupp3t1@', | ||
} } | ||
let(:facts) { {:osfamily => 'windows', :platform => :windows} } | ||
describe 'compile' do | ||
it { | ||
should contain_file('C:/Program Files/Microsoft SQL Server/.puppet/.MSSQLSERVER.cfg') | ||
should contain_file('C:/Program Files/Microsoft SQL Server/.puppet') | ||
} | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
require 'spec_helper' | ||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'manifest_shared_examples.rb')) | ||
|
||
describe 'sqlserver::user::permission' do | ||
let(:facts) { {:osfamily => 'windows'} } | ||
context 'validation errors' do | ||
include_context 'manifests' do | ||
let(:title) { 'myTitle' } | ||
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' } | ||
end | ||
context 'user =>' do | ||
let(:params) { { | ||
:permission => 'SELECT', | ||
:database => 'loggingDb', | ||
} } | ||
let(:raise_error_check) { 'User must be between 1 and 128 characters' } | ||
describe 'missing' do | ||
let(:raise_error_check) { 'Must pass user to Sqlserver::User::Permission[myTitle]' } | ||
it_behaves_like 'validation error' | ||
end | ||
describe 'empty' do | ||
let(:additional_params) { {:user => ''} } | ||
it_behaves_like 'validation error' | ||
end | ||
describe 'over limit' do | ||
let(:additional_params) { {:user => random_string_of_size(129)} } | ||
end | ||
end | ||
context 'permission' do | ||
let(:params) { { | ||
:user => 'loggingUser', | ||
:database => 'loggingDb', | ||
} } | ||
let(:raise_error_check) { 'Permission must be between 4 and 128 characters' } | ||
describe 'empty' do | ||
let(:additional_params) { {:permission => ''} } | ||
it_behaves_like 'validation error' | ||
end | ||
describe 'under limit' do | ||
let(:additional_params) { {:permission => random_string_of_size(3, false)} } | ||
it_behaves_like 'validation error' | ||
end | ||
describe 'over limit' do | ||
let(:additional_params) { {:permission => random_string_of_size(129, false)} } | ||
it_behaves_like 'validation error' | ||
end | ||
end | ||
context 'state =>' do | ||
let(:params) { { | ||
:permission => 'SELECT', | ||
:database => 'loggingDb', | ||
:user => 'loggingUser' | ||
} } | ||
describe 'invalid' do | ||
let(:additional_params) { {:state => 'invalide'} } | ||
let(:raise_error_check) { "State can only be of 'GRANT', 'REVOKE' or 'DENY' you passed invalide" } | ||
it_behaves_like 'validation error' | ||
end | ||
end | ||
end | ||
context 'successfully' do | ||
include_context 'manifests' do | ||
let(:title) { 'myTitle' } | ||
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' } | ||
let(:params) { { | ||
:user => 'loggingUser', | ||
:permission => 'SELECT', | ||
:database => 'loggingDb', | ||
} } | ||
end | ||
%w(revoke grant deny).each do |state| | ||
context "state => '#{state}'" do | ||
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-#{state.upcase}-SELECT" } | ||
let(:should_contain_command) { ["#{state.upcase} SELECT TO [loggingUser];", 'USE [loggingDb];'] } | ||
describe "lowercase #{state}" do | ||
let(:additional_params) { {:state => state} } | ||
it_behaves_like 'sqlserver_tsql command' | ||
end | ||
state.capitalize! | ||
describe "capitalized #{state}" do | ||
let(:additional_params) { {:state => state} } | ||
it_behaves_like 'sqlserver_tsql command' | ||
end | ||
end | ||
end | ||
|
||
context 'permission' do | ||
describe 'upper limit' do | ||
permission =random_string_of_size(128, false) | ||
let(:additional_params) { {:permission => permission} } | ||
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-#{permission.upcase}" } | ||
let(:should_contain_command) { ['USE [loggingDb];'] } | ||
it_behaves_like 'sqlserver_tsql command' | ||
end | ||
describe 'alter' do | ||
let(:additional_params) { {:permission => 'ALTER'} } | ||
let(:should_contain_command) { ['USE [loggingDb];', 'GRANT ALTER TO [loggingUser];'] } | ||
let(:sqlserver_tsql_title) { "user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-ALTER" } | ||
it_behaves_like 'sqlserver_tsql command' | ||
end | ||
end | ||
|
||
describe 'Minimal Params' do | ||
let(:pre_condition) { <<-EOF | ||
define sqlserver::config{} | ||
sqlserver::config {'MSSQLSERVER': } | ||
EOF | ||
} | ||
let(:should_contain_command) { ['USE [loggingDb];'] } | ||
it_behaves_like 'compile' | ||
end | ||
|
||
end | ||
|
||
context 'command syntax' do | ||
include_context 'manifests' do | ||
let(:title) { 'myTitle' } | ||
let(:sqlserver_tsql_title) { 'user-permissions-MSSQLSERVER-loggingDb-loggingUser-GRANT-SELECT' } | ||
let(:params) { { | ||
:user => 'loggingUser', | ||
:permission => 'SELECT', | ||
:database => 'loggingDb', | ||
} } | ||
describe '' do | ||
let(:should_contain_command) { [ | ||
'USE [loggingDb];', | ||
'GRANT SELECT TO [loggingUser];', | ||
/DECLARE @perm_state varchar\(250\)/, | ||
/SET @perm_state = ISNULL\(\n\s+\(SELECT perm.state_desc FROM sys\.database_principals princ\n\s+JOIN sys\./, | ||
/JOIN sys\.database_permissions perm ON perm\.grantee_principal_id = princ.principal_id\n\s+WHERE/, | ||
/WHERE princ\.type in \('U','S','G'\) AND name = 'loggingUser' AND permission_name = 'SELECT' \),\n\s+'REVOKE'\);/, | ||
/DECLARE @error_msg varchar\(250\);\nSET @error_msg = 'EXPECTED user \[loggingUser\] to have permission \[SELECT\] with GRANT but got ' \+ @perm_state;/, | ||
/IF @perm_state != 'GRANT'\n\s+THROW 51000, @error_msg, 10/ | ||
] } | ||
it_behaves_like 'sqlserver_tsql command' | ||
end | ||
end | ||
end | ||
|
||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
BEGIN | ||
USE [<%= @database %>]; | ||
<%= @_state %> <%= @_permission %> TO [<%= @user %>]; | ||
END | ||
BEGIN | ||
<%= scope.function_template(['sqlserver/query/user_permission_exists.sql.erb']) %> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. I wouldn't have thought in module you would need to namespace it. TIL There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe when calling from another template you have to. Inside a Puppet Policy file however that might be different. |
||
END |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
USE [<%= @database %>]; | ||
DECLARE @perm_state varchar(250); | ||
SET @perm_state = ISNULL( | ||
(SELECT perm.state_desc FROM sys.database_principals princ | ||
JOIN sys.database_permissions perm ON perm.grantee_principal_id = princ.principal_id | ||
WHERE princ.type in ('U','S','G') AND name = '<%= @user %>' AND permission_name = '<%= @_permission %>' ), | ||
'REVOKE'); | ||
DECLARE @error_msg varchar(250); | ||
SET @error_msg = 'EXPECTED user [<%= @user %>] to have permission [<%= @_permission %>] with <%= @_state %> but got ' + @perm_state; | ||
IF @perm_state != '<%= @_state %>' | ||
THROW 51000, @error_msg, 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How specific are we setting permissions? This doesn't appear specific enough to pass a security audit/SOx review. Perms at db level may be considered too broad. At least consider also adding ability to go down to object level.