-
Notifications
You must be signed in to change notification settings - Fork 21
FM-2287 Add Role Permissions ability #76
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
25ac79c
bd8d2fa
043b2fa
311fd63
ff9ad36
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 |
---|---|---|
@@ -0,0 +1,28 @@ | ||
module Puppet::Parser::Functions | ||
newfunction(:sqlserver_upcase, :type => :rvalue, :arity => 1) do |arguments| | ||
|
||
raise(Puppet::ParseError, "upcase(): Wrong number of arguments " + | ||
"given (#{arguments.size} for 1)") if arguments.size != 1 | ||
|
||
value = arguments[0] | ||
|
||
unless value.is_a?(Array) || value.is_a?(Hash) || value.respond_to?(:upcase) | ||
raise(Puppet::ParseError, 'upcase(): Requires an ' + | ||
'array, hash or object that responds to upcase in order to work') | ||
end | ||
|
||
if value.is_a?(Array) | ||
# Numbers in Puppet are often string-encoded which is troublesome ... | ||
result = value.collect { |i| function_sqlserver_upcase([i]) } | ||
elsif value.is_a?(Hash) | ||
result = {} | ||
value.each_pair do |k, v| | ||
result[function_sqlserver_upcase([k])] = function_sqlserver_upcase([v]) | ||
end | ||
else | ||
result = value.upcase | ||
end | ||
|
||
return result | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
## | ||
# == Define Resource Type: sqlserver::role::permissions | ||
# | ||
# | ||
# === Requirement/Dependencies: | ||
# | ||
# Requires defined type {sqlserver::config} in order to execute against the SQL Server instance | ||
# | ||
# | ||
# === Parameters | ||
# | ||
# [ensure] | ||
# Whether the role should be absent or present | ||
# | ||
# [role] | ||
# The name of the role for which the permissions will be manage. | ||
# | ||
# [instance] | ||
# The name of the instance where the role and database exists. Defaults to 'MSSQLSERVER' | ||
# | ||
# [authorization] | ||
# The database principal that should own the role | ||
# | ||
# [type] | ||
# Whether the Role is `SERVER` or `DATABASE` | ||
# | ||
# [database] | ||
# The name of the database the role exists on when specifying `type => 'DATABASE'`. Defaults to 'master' | ||
# | ||
# [permissions] | ||
# A hash of permissions that should be managed for the role. Valid keys are 'GRANT', 'GRANT_WITH_OPTION', 'DENY' or 'REVOKE'. Valid values must be an array of Strings i.e. {'GRANT' => ['CONNECT', 'CREATE ANY DATABASE'] } | ||
# | ||
## | ||
define sqlserver::role( | ||
$ensure = present, | ||
$role = $title, | ||
$instance = 'MSSQLSERVER', | ||
$authorization = undef, | ||
$type = 'SERVER', | ||
$database = 'master', | ||
$permissions = { }, | ||
){ | ||
sqlserver_validate_instance_name($instance) | ||
sqlserver_validate_range($role, 1, 128, 'Role names must be between 1 and 128 characters') | ||
|
||
validate_re($type, ['^SERVER$','^DATABASE$'], "Type must be either 'SERVER' or 'DATABASE', provided '${type}'") | ||
|
||
sqlserver_validate_range($database, 1, 128, 'Database name must be between 1 and 128 characters') | ||
if $type == 'SERVER' and $database != 'master' { | ||
fail('Can not specify a database other than master when managing SERVER ROLES') | ||
} | ||
|
||
$_create_delete = $ensure ? { | ||
present => 'create', | ||
absent => 'delete', | ||
} | ||
|
||
sqlserver_tsql{ "role-${role}-${instance}": | ||
command => template("sqlserver/${_create_delete}/role.sql.erb"), | ||
onlyif => template('sqlserver/query/role_exists.sql.erb'), | ||
instance => $instance, | ||
} | ||
|
||
if $ensure == present { | ||
validate_hash($permissions) | ||
$_upermissions = sqlserver_upcase($permissions) | ||
|
||
Sqlserver::Role::Permissions{ | ||
role => $role, | ||
instance => $instance, | ||
database => $database, | ||
type => $type, | ||
require => Sqlserver_tsql["role-${role}-${instance}"] | ||
} | ||
if has_key($_upermissions, 'GRANT') and is_array($_upermissions['GRANT']) { | ||
sqlserver::role::permissions{ "Sqlserver::Role[${title}]-GRANT-${role}": | ||
state => 'GRANT', | ||
permissions => $_upermissions['GRANT'], | ||
} | ||
} | ||
if has_key($_upermissions, 'DENY') and is_array($_upermissions['DENY']) { | ||
sqlserver::role::permissions{ "Sqlserver::Role[${title}]-DENY-${role}": | ||
state => 'DENY', | ||
permissions => $_upermissions['DENY'], | ||
} | ||
} | ||
if has_key($_upermissions, 'REVOKE') and is_array($_upermissions['REVOKE']) { | ||
sqlserver::role::permissions{ "Sqlserver::Role[${title}]-REVOKE-${role}": | ||
state => 'REVOKE', | ||
permissions => $_upermissions['REVOKE'], | ||
} | ||
} | ||
if has_key($_upermissions, 'GRANT_WITH_OPTION') and is_array($_upermissions['GRANT_WITH_OPTION']) { | ||
sqlserver::role::permissions{ "Sqlserver::Role[${title}]-GRANT-WITH_GRANT_OPTION-${role}": | ||
state => 'GRANT', | ||
with_grant_option => true, | ||
permissions => $_upermissions['GRANT_WITH_OPTION'], | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
## | ||
# == Define Resource Type: sqlserver::role::permissions | ||
# | ||
# | ||
# === Requirement/Dependencies: | ||
# | ||
# Requires defined type {sqlserver::config} in order to execute against the SQL Server instance | ||
# | ||
# | ||
# === Parameters | ||
# [role] | ||
# The name of the role for which the permissions will be manage. | ||
# | ||
# [permissions] | ||
# An array of permissions you want manged for the given role | ||
# | ||
# [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. | ||
# | ||
# [with_grant_option] | ||
# Whether to give the role the option to grant this permission to other principal objects, accepts true or false, defaults to false | ||
# | ||
# [type] | ||
# Whether the Role is `SERVER` or `DATABASE` | ||
# | ||
# [database] | ||
# The name of the database the role exists on when specifying `type => 'DATABASE'`. Defaults to 'master' | ||
# | ||
# [instance] | ||
# The name of the instance where the role and database exists. Defaults to 'MSSQLSERVER' | ||
# | ||
## | ||
define sqlserver::role::permissions ( | ||
$role, | ||
$permissions, | ||
$state = 'GRANT', | ||
$with_grant_option = false, | ||
$type = 'SERVER', | ||
$database = 'master', | ||
$instance = 'MSSQLSERVER', | ||
){ | ||
validate_array($permissions) | ||
if size($permissions) < 1 { | ||
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. This is before 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. we validate later if it is an array as well, so if it was an string of x numbers we would still fail after that as it would fail validate_array |
||
warning("Received an empty set of permissions for ${title}, no further action will be taken") | ||
} else{ | ||
sqlserver_validate_instance_name($instance) | ||
#Validate state | ||
$_state = upcase($state) | ||
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. Still upcase 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. A simple string, stdlib should work fine |
||
validate_re($_state,'^(GRANT|REVOKE|DENY)$',"State can only be of 'GRANT', 'REVOKE' or 'DENY' you passed ${state}") | ||
validate_bool($with_grant_option) | ||
|
||
#Validate role | ||
sqlserver_validate_range($role, 1, 128, 'Role names must be between 1 and 128 characters') | ||
|
||
#Validate permissions | ||
sqlserver_validate_range($permissions, 4, 128, 'Permissions must be between 4 and 128 characters') | ||
|
||
$_upermissions = upcase($permissions) | ||
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. Still upcase 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. A simple string, stdlib should work fine |
||
|
||
$_grant_option = $with_grant_option ? { | ||
true => '-WITH_GRANT_OPTION', | ||
false => '', | ||
} | ||
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. This will fail with future parser/strict variables 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. Good catch, will fix. |
||
## | ||
# Parameters required in template are _state, role, _upermissions, database, type, with_grant_option | ||
## | ||
sqlserver_tsql{ "role-permissions-${role}-${_state}${_grant_option}-${instance}": | ||
instance => $instance, | ||
command => template('sqlserver/create/role/permissions.sql.erb'), | ||
onlyif => template('sqlserver/query/role/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. Can you list the variables used in the templates in a comment? |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
require 'spec_helper' | ||
|
||
RSpec.describe 'sqlserver::role::permissions' do | ||
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. Why is this 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. RSpec.describe is rspec 3 syntax. But only for top level items |
||
include_context 'manifests' do | ||
let(:title) { 'myTitle' } | ||
let(:sqlserver_tsql_title) { 'role-permissions-myCustomRole-GRANT-MSSQLSERVER' } | ||
let(:params) { { | ||
:role => 'myCustomRole', | ||
:permissions => %w(INSERT UPDATE DELETE SELECT), | ||
} } | ||
end | ||
|
||
context 'sql variables' do | ||
let(:params) { { | ||
:role => 'myCustomRole', | ||
:permissions => %w(INSERT UPDATE DELETE SELECT), | ||
} } | ||
declare_variables = [ | ||
"DECLARE | ||
@perm_state varchar(250), | ||
@error_msg varchar(250), | ||
@permission varchar(250), | ||
@princ_name varchar(50), | ||
@princ_type varchar(50), | ||
@state_desc varchar(50);", | ||
"SET @princ_type = 'SERVER_ROLE';", | ||
"SET @princ_name = 'myCustomRole';", | ||
"SET @state_desc = 'GRANT';"] | ||
let(:should_contain_command) { declare_variables } | ||
let(:should_contain_onlyif) { declare_variables } | ||
it_behaves_like 'sqlserver_tsql command' | ||
it_behaves_like 'sqlserver_tsql onlyif' | ||
end | ||
|
||
context 'type =>' do | ||
shared_examples 'GRANT Permissions' do |type| | ||
base_commands = [ | ||
"SET @princ_type = '#{type.upcase}_ROLE';", | ||
"ISNULL( | ||
(SELECT state_desc FROM sys.#{type.downcase}_permissions prem | ||
JOIN sys.#{type.downcase}_principals r ON r.principal_id = prem.grantee_principal_id | ||
WHERE r.name = @princ_name AND r.type_desc = @princ_type | ||
AND prem.permission_name = @permission), | ||
'REVOKE')", | ||
"SET @permission = 'INSERT';", | ||
"SET @permission = 'UPDATE';", | ||
"SET @permission = 'DELETE';", | ||
"SET @permission = 'SELECT';", | ||
] | ||
should_commands = [ | ||
"GRANT INSERT TO [myCustomRole];", | ||
"GRANT UPDATE TO [myCustomRole];", | ||
"GRANT DELETE TO [myCustomRole];", | ||
"GRANT SELECT TO [myCustomRole];" | ||
] | ||
let(:should_contain_command) { base_commands + should_commands } | ||
let(:should_contain_onlyif) { base_commands } | ||
it_behaves_like 'sqlserver_tsql command' | ||
it_behaves_like 'sqlserver_tsql onlyif' | ||
end | ||
|
||
describe 'DATABASE' do | ||
let(:additional_params) { { | ||
:type => 'DATABASE', | ||
} } | ||
it_behaves_like 'GRANT Permissions', 'database' | ||
end | ||
|
||
describe 'SERVER' do | ||
let(:additional_params) { { | ||
:type => 'SERVER', | ||
} } | ||
it_behaves_like 'GRANT Permissions', 'server' | ||
end | ||
end | ||
|
||
context 'permissions =>' do | ||
describe '[INSERT UPDATE DELETE SELECT]' do | ||
declare_variables = [ | ||
"SET @permission = 'INSERT';", | ||
"SET @permission = 'UPDATE';", | ||
"SET @permission = 'DELETE';", | ||
"SET @permission = 'SELECT';", | ||
] | ||
let(:should_contain_command) { declare_variables + | ||
[ | ||
"GRANT INSERT TO [myCustomRole];", | ||
"GRANT UPDATE TO [myCustomRole];", | ||
"GRANT DELETE TO [myCustomRole];", | ||
"GRANT SELECT TO [myCustomRole];" | ||
] } | ||
let(:should_contain_onlyif) { declare_variables } | ||
it_behaves_like 'sqlserver_tsql command' | ||
it_behaves_like 'sqlserver_tsql onlyif' | ||
end | ||
describe '[]' do | ||
let(:params) { { | ||
:role => 'myCustomRole', | ||
:permissions => [] | ||
} } | ||
it { | ||
should compile | ||
should_not contain_sqlserver_tsql(sqlserver_tsql_title) | ||
} | ||
end | ||
end | ||
|
||
context 'database =>' do | ||
describe 'default' do | ||
let(:should_contain_command) { ['USE [master];'] } | ||
let(:should_contain_onlyif) { ['USE [master];'] } | ||
it_behaves_like 'sqlserver_tsql command' | ||
it_behaves_like 'sqlserver_tsql onlyif' | ||
end | ||
describe 'customDatabase' do | ||
let(:additional_params) { {:database => 'customDatabase'} } | ||
let(:should_contain_command) { ['USE [customDatabase];'] } | ||
it_behaves_like 'sqlserver_tsql command' | ||
let(:should_contain_onlyif) { ['USE [customDatabase];'] } | ||
it_behaves_like 'sqlserver_tsql onlyif' | ||
let(:should_contain_without_command) { ['USE [master];'] } | ||
it_behaves_like 'sqlserver_tsql without_command' | ||
let(:should_contain_without_onlyif) { ['USE [master];'] } | ||
it_behaves_like 'sqlserver_tsql without_onlyif' | ||
end | ||
end | ||
|
||
context 'instance =>' do | ||
['MSSQLSERVER', 'MYINSTANCE'].each do |instance| | ||
describe "should contain #{instance} for sqlserver_tsql" do | ||
let(:params) { { | ||
:role => 'myCustomRole', | ||
:permissions => %w(INSERT UPDATE DELETE SELECT), | ||
:instance => instance | ||
} } | ||
it { | ||
should contain_sqlserver_tsql("role-permissions-myCustomRole-GRANT-#{instance}").with_instance(instance) | ||
} | ||
end | ||
end | ||
end | ||
|
||
end |
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.
Can you list the variables used in the templates in a comment?