Windows 和 .NET 中的凭据链接序列出现问题

本文关键字:问题 链接 NET Windows | 更新日期: 2023-09-27 17:56:17

问题摘要

当以批处理模式运行时,我的用户身份会丢失,但(就像一个非常好的悬崖峭壁)直到最后一刻。

问题详情

我有一个在WinXpSp3上运行的PowerShell脚本,该脚本在后台(通过-AsJob参数)作为特定测试用户(通过-Session参数)在远程计算机上运行脚本块(通过Invoke-Command)。会话是通过以下方式创建的:

New-PSSession -computername $myServer -credential $myCredential

脚本块执行许多操作,最终运行 NUnit 测试框架。测试中的C#代码记录了"myTestUser"用户名(通过Environment.UserName),因此到目前为止,PowerShell提供的凭据可以正确接收。Process Explorer进一步证实了这一点:检查运行批处理测试的nunit控制台的属性表明它归myTestUser所有。

该测试包括访问 Sql Server 2008 R2 数据库;连接字符串是通过new SqlConnection(connectionString)调用设置的。连接字符串是为 Windows 身份验证设置的,并使用以下形式:

Data Source=<my_db_server_name>;Initial Catalog=<my_db_name>;Integrated Security=True;Persist Security Info=True

即使我最终将 myTestUser 凭据一直推送到受测的 C# 代码,数据库访问尝试也没有看到这些凭据,从而导致此错误: 用户"NT 权限''匿名登录"登录失败

一些补充信息:

  1. 我已确认测试用户 (myTestUser) 具有数据库权限,并且 NUnit 测试能够访问数据库:当我以 myTestUser 身份登录的手动运行 NUnit 测试(通过 NUnit GUI)时,测试工作正常,并且 SqlProfiler 清楚地显示了此活动,myTestUser 出现在 NTUserName 列中。
  2. 如果我在本地而不是在远程计算机上运行,则会发生相同的错误。
  3. 如果我在本地机器上以自己的身份运行(即省略 -credential 参数),也会发生同样的错误。

问题

我怎样才能将myTestUser从厄运的边缘拯救出来,并让他获得数据库访问权限?


2011.05.16 更新

下面是一个显示相同问题的简化示例。

首先,我的测试程序DBFetchVersion打印当前用户的名称和简单查询的结果:

class Program
{
    const string connString = ...your connection string here... ;
    const string query = "SELECT getdate() [Date], substring(@@version,1,charindex('-',@@version)-1) +convert(varchar(100),SERVERPROPERTY('edition'))+ ' ' +convert(varchar(100),SERVERPROPERTY('productlevel')) [SQL Server Version], @@servicename [Service Name], @@servername [Server Host], db_name() [Database], user_name() [User], host_name() [Client]";
    static void Main(string[] args)
    {
        DataView dataView;
        using (var connection = new SqlConnection(connString))
        {
            Console.WriteLine("user = " + Environment.UserName);
            using (var dataAdapter = new SqlDataAdapter(query, connection))
            {
                var dataSet = new DataSet();
                try
                {
                    connection.Open();
                    dataAdapter.SelectCommand.CommandType = CommandType.Text;
                    dataAdapter.Fill(dataSet, query);
                }
                finally { if (connection.State == ConnectionState.Open) connection.Close(); }
                dataView = dataSet.Tables[0].DefaultView;
            }
            foreach (var item in dataView.Table.Rows[0].ItemArray)
                Console.WriteLine(item);
        }
    }
}

这是调用上述程序的Powershell脚本。

$scriptBlock = {
    & "...path to my executable...'DBFetchVersion'bin'Debug'DBFetchVersion.exe"
}
$serverName = ... my server name ...
$username = "testuser"
$password = ... my user password ...
$adjPwd = $password | ConvertTo-SecureString -asPlainText -Force
$testCred = (New-Object System.Management.Automation.PSCredential($username,$adjPwd))    
$mySession = New-PSSession -computername $serverName  -credential $testCred 
# Test Scenarios:
Invoke-Command $scriptBlock 
#Invoke-Command $scriptBlock -computername $serverName 
#Invoke-Command $scriptBlock -computername $serverName  -credential $testCred 
#Invoke-Command $scriptBlock -Session $mySession 

在最后的四个测试方案列表中,未注释的测试方案有效,打印我的用户名和查询结果。DBFetchVersion 仍然报告我是第二行的用户,但数据库连接失败,并显示"用户'NT AUTHORITY''ANONYMOUS 登录'登录失败"错误。其余两行报告"testuser"用户名,但都报告数据库连接的相同登录失败。

这个孤立的例子告诉我的并不是我认为Powershell,.NET或我的代码有任何错误,而是身份验证机制中有一些我还不了解的东西,因为指定另一台计算机或会话都涉及路径,从某种意义上说,应该具有更强的保护。

2011.08.03 更新 - 尤里卡!

好吧,Matt 正确地将双跳问题确定为罪魁祸首,将 CredSSP 身份验证确定为解决方案。不幸的是,正如我很快发现的那样,CredSSP需要Windows 7,所以我开始设置几个VM作为沙盒。然而,CredSSP不是一个轻易放弃其秘密的人(至少对我来说),正如我在ServerFault上的这篇文章中所详述的那样:无法让CredSSP身份验证在PowerShell中工作。

我终于能够让 CredSSP 身份验证正常工作,这样我就可以回到我在此线程中提出的问题。作为测试,我使用了插入到上面提供的PowerShell脚本中的以下3个脚本块:

$scriptBlockA = {
    Write-Host ("hello, world: {0}, {1}" -f $env:USERNAME, (hostname))
}
# Simple DB test, but requires SqlServer installed!
$scriptBlockB = {
    if (! (Get-PSSnapin | ? { $_.name -eq "SqlServerCmdletSnapin100" } ) )
    { Add-PSSnapin SqlServerCmdletSnapin100; }
    Invoke-Sqlcmd -Query "SELECT getdate() as [Now]" -ServerInstance CinDevDB5
}
# Indirect DB test; requires .NET but not SqlServer,
# plus DBFetchVersion in home dir for targeted user.
$scriptBlockC = {
    & ".'DBFetchVersion.exe"
}

A块使用或不使用CredSSP,因为没有双跳。块 B 和 C 仅适用于 CredSSP,因为它们都尝试访问远程数据库。QED。

Windows 和 .NET 中的凭据链接序列出现问题

最初我读到这篇文章并想到了"双跳"问题,但补充信息可能让我质疑这一点。

当您在本地运行它(作为您自己或测试用户)时,您使用什么命令? 这个:

& "...path to my executable...'DBFetchVersion'bin'Debug'DBFetchVersion.exe"

也可以从本地计算机(作为您自己或用户)执行此工作:

Add-PSSnapin SqlServerCmdletSnapin100;
Invoke-Sqlcmd -Query "SELECT getdate()" -ServerInstance Server

还有你用的是什么操作系统?如果是Windows 2008并且问题是双跳,您可以向我们CredSSP避免它。