diff --git a/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb b/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb index 0f7e806e..549c2f3a 100644 --- a/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb +++ b/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb @@ -777,7 +777,7 @@ def prepare_credentials(resource) variable_name = random_variable_name credential_hash = { 'user' => property_hash[:value]['user'], - 'password' => escape_quotes(property_hash[:value]['password'].unwrap) + 'password' => escape_quotes(unwrap_string(property_hash[:value]['password'])) } credentials_block << format_pscredential(variable_name, credential_hash) instantiated_variables.merge!(variable_name => credential_hash) @@ -908,7 +908,7 @@ def invoke_params(resource) # the Credential hash interpolable as it will be replaced by a variable reference. { 'user' => property_hash[:value]['user'], - 'password' => escape_quotes(property_hash[:value]['password'].unwrap) + 'password' => escape_quotes(unwrap_string(property_hash[:value]['password'])) } when 'DateTime' # These have to be handled specifically because they rely on the *Puppet* DateTime, @@ -1001,6 +1001,31 @@ def unwrap(value) end end + # Unwrap sensitive strings and handle string + # + # @param value [Object] The object to unwrap sensitive data inside of + # @return [Object] The object with any sensitive strings unwrapped + def unwrap_string(value) + case value + when Puppet::Pops::Types::PSensitiveType::Sensitive + value.unwrap + when Hash + unwrapped = {} + value.each do |k, v| + unwrapped[k] = unwrap_string(v) + end + unwrapped + when Array + unwrapped = [] + value.each do |v| + unwrapped << unwrap_string(v) + end + unwrapped + else + value + end + end + # Escape any nested single quotes in a Sensitive string # # @param text [String] the text to escape diff --git a/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb b/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb index 23089cc6..5389121b 100644 --- a/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb +++ b/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb @@ -439,7 +439,7 @@ mof_is_embedded: false }, dsc_psdscrunascredential: { - type: 'Optional[Struct[{ user => String[1], password => Sensitive[String[1]] }]]', + type: 'Optional[Struct[{ user => String[1], password => Variant[String[1], Sensitive[String[1]]] }]]', behaviour: :parameter, mandatory_for_get: false, mandatory_for_set: false, @@ -886,7 +886,7 @@ mof_is_embedded: false }, dsc_psdscrunascredential: { - type: 'Optional[Struct[{ user => String[1], password => Sensitive[String[1]] }]]', + type: 'Optional[Struct[{ user => String[1], password => Variant[String[1], Sensitive[String[1]]] }]]', desc: 'The Credential to run DSC under', behaviour: :parameter, mandatory_for_get: false, @@ -1552,6 +1552,8 @@ let(:test_resource) { base_resource.merge(additional_parameters) } before do + allow(Puppet::Pops::Types::PSensitiveType::Sensitive).to receive(:===).with(foo_password).and_return(true) + allow(Puppet::Pops::Types::PSensitiveType::Sensitive).to receive(:===).with(bar_password).and_return(true) allow(foo_password).to receive(:unwrap).and_return('foo') allow(bar_password).to receive(:unwrap).and_return('bar') end @@ -1791,6 +1793,11 @@ "$InvokeParams = @{Name = 'Foo'; Method = 'Get'; Property = @{credential = $SomeCredential}; ModuleName = 'PuppetDsc'}" end + before do + allow(Puppet::Pops::Types::PSensitiveType::Sensitive).to receive(:===).with(password).and_return(true) + allow(password).to receive(:unwrap).and_return('bar') + end + it 'unwraps the credential hash and interpolates the appropriate variable' do expect(password).to receive(:unwrap).and_return('FooPassword') expect(provider).to receive(:interpolate_variables).with(formatted_param_hash).and_return(variable_interpolated_param_hash)