如何将SecureString从PSCredential传递给NetworkCredential?

时间:2013-09-24 06:32:48

标签: httpwebrequest powershell-v2.0

注意:我不能在这里使用PowerShell V3.0,否则我将使用Invoke-WebRequest并过上幸福的生活。

我有一个PowerShell V2.0脚本,需要将数据POST到HTTP-Basic认证资源。出于脚本的目的,我不想或不需要知道用户的密码,我只想将PSCredentials对象(从PromptForCredential返回)转换为NetworkCredential以与HttpWebRequest一起使用。

$uri = "https://example.com/some/resource/"

# Get our user's credentials...
$defaultUsername = "Some Username"
$caption = "Authentication required"
$message = "A username and password is required for ${uri}"
#$target = $uri #<<--NOTE: This prepends $uri+"\" to the username.
#$target = "" #<<--NOTE: This prepends "\" to the username.
$target = $null #<<--NOTE: This still prepends "\" to the username.
$psCredential = $Host.UI.PromptForCredential($caption, $message, $defaultUsername, $target)

# Construct a CredentialCache for HttpWebRequest...
# NOTE: We need to delete the "domain part" of the username from the PSCrential.Username, otherwise we get "Something\Username"
$username = ($psCredential.Username).Split('\')[1]
$networkCredential = New-Object System.Net.NetworkCredential($username, [System.Security.SecureString]$psCredential.Password)
$credentialCache = New-Object System.Net.CredentialCache
$credentialCache.Add( (New-Object Uri($uri)), "Basic", $networkCredential)

#...
$request = New-Object System.Net.HttpWebRequest($uri)
$request.Credentials = $credentialCache
#...
[System.Net.HttpWebResponse]$response = [System.Net.HttpWebResponse]$request.GetResponse()

这当然失败了,例外:

Exception calling "GetResponse" with "0" argument(s):
"The remote server returned an error: (401) Unauthorized."

据称我们有一个NetworkCredential(String userName,SecureString password)构造函数,但是用户的凭据以用户名的形式到达服务器:System.Security.SecureString。

我缺少一些细节吗?我是否需要解密SecureString并将其传递给NetworkCredential(String userName,String password)构造函数?

2 个答案:

答案 0 :(得分:0)

我发现了问题... NetworkCredential(String userName,SecureString password)构造函数仅从.NET Framework 4.0开始提供。当然,PowerShell 2.0在.NET 2.0中运行。

虽然有一些方法和方法可以在.NET 4.0中运行PowerShell 2.0,但我不能自由地改变运行时环境的配置。

相反,我走了“Unsecure String”路径。根据文章“How to properly convert SecureString to String”,我创建了这个PowerShell函数:

function Convert-To-Unsecure-String {
        Param(
            [Parameter(HelpMessage="The SecureString object to make a very unsecure String")]
            [ValidateNotNull()]
            [System.Security.SecureString]
            $securePassword
        )
        $unmanagedString = [System.IntPtr]::Zero
        try {
            $unmanagedString = [Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($securePassword);
            return [Runtime.InteropServices.Marshal]::PtrToStringUni($unmanagedString);
        }
        finally {
            [Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($unmanagedString);
        }
}

将原始示例的NetworkCredential构造函数替换为:

$networkCredential = New-Object System.Net.NetworkCredential($username, (Convert-To-Unsecure-String($psCredential.Password)) )

现在我在服务器上获得了正确的base64编码“username:password”字符串。

答案 1 :(得分:0)

我遇到了同样的问题。我的修复非常简单。不要在用户名中包含域名。我试图连接到JIRA来运行JQL。

不要这样做 $ userName = Me @ Mydomain;或$ userName = MyDomain / Me 但是那样做 $ userName = Me