Parameter `secureString` transforms input incorrectly on adapter
Prerequisites
- [x] Write a descriptive title.
- [x] Make sure you are able to repro it on the latest version
- [x] Search the existing issues.
Summary
Whilst working on #1208, another issue popped up. I have the following configuration document:
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
myString:
type: secureString
defaultValue: "MySecret"
resources:
- name: Class-resource Info
type: TestClassResource/TestClassResource
properties:
Name: 'TestClassResource'
SecureStringProp: "[parameters('myString')]"
Instead of parsing the input through the adapter as such (seen in the logging):
{"resources":[{"name":"TestClassResource/TestClassResource","type":"TestClassResource/TestClassResource","properties":{"Name":"TestClassResource","SecureStringProp":"MySecret"}}],"metadata":{"Microsoft.DSC":{"context":"configuration"}}}
It does it like:
jsonInput={"resources":[{"name":"TestClassResource/TestClassResource","type":"TestClassResource/TestClassResource","properties":{"Name":"TestClassResource","SecureStringProp":{"secureString":"MySecret"}}}],"metadata":{"Microsoft.DSC":{"context":"configuration"}}}
Which results in the following error: Exception setting "SecureStringProp": "Cannot create object of type "System.Security.SecureString". The property 'secureString' was not found for the 'System.Security.SecureString' object. There is no settable property available."
Steps to reproduce
See steps above.
Expected behavior
The secure string is parsed as string
Actual behavior
The secure string is parsed as object
Error details
Environment data
Name Value
---- -----
PSVersion 7.5.3
PSEdition Core
GitCommitId 7.5.3
OS Microsoft Windows 10.0.26100
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Version
dsc 3.2.0-preview.6
Visuals
No response
@SteveL-MSFT - I tried debugging this myself and look back to the history what has happened here.
Basically, I just removed the object type (seen in the history) for string to something like:
se crate::configure::config_doc::DataType;
use crate::configure::parameters::{SecureObject};
use crate::DscError;
use crate::configure::context::Context;
use crate::functions::{FunctionArgKind, Function, FunctionCategory, FunctionMetadata};
use rust_i18n::t;
use serde_json::Value;
use tracing::{debug, trace};
#[derive(Debug, Default)]
pub struct Parameters {}
impl Function for Parameters {
fn get_metadata(&self) -> FunctionMetadata {
FunctionMetadata {
name: "parameters".to_string(),
description: t!("functions.parameters.description").to_string(),
category: vec![FunctionCategory::Deployment],
min_args: 1,
max_args: 1,
accepted_arg_ordered_types: vec![vec![FunctionArgKind::String]],
remaining_arg_accepted_types: None,
return_types: vec![FunctionArgKind::String, FunctionArgKind::Number, FunctionArgKind::Boolean, FunctionArgKind::Object, FunctionArgKind::Array, FunctionArgKind::Null],
}
}
fn invoke(&self, args: &[Value], context: &Context) -> Result<Value, DscError> {
debug!("{}", t!("functions.parameters.invoked"));
if let Some(key) = args[0].as_str() {
trace!("{}", t!("functions.parameters.traceKey", key = key));
if context.parameters.contains_key(key) {
let (value, data_type) = &context.parameters[key];
match data_type {
DataType::SecureString => {
let Some(_value) = value.as_str() else {
return Err(DscError::Parser(t!("functions.parameters.keyNotString", key = key).to_string()));
};
},
// truncated
Now I'm not certain, nor did I gave feedback during that PR, what the design choice was to transform the secure string to an object. As mentioned in the PR, I can see that resources should handle this, but is this also the case for adapters? If so, a second option would be to read it in the adapter, and simply strip away the object type.
Another option would be (which I haven't checked out) to let the adapter code handle it 🤔. Any thoughts are welcome.
@Gijsreyn the intent for that original PR was the secureString and secureObject needed to maintain their "object-ness" and rely on resources to handle them appropriately. This is also true for adapters. In this case, the psadapter needs to see if the property value is of one of these types and convert it to the correct PowerShell/.NET type.