Сводка проблемы
При запуске в пакетном режиме моя личность теряется, но (как действительно хороший скафандр) только до самого последнего момента.
Детали проблемы
У меня есть сценарий PowerShell, работающий на WinXpSp3, который запускает блок сценария (через Invoke-Command) на удаленной машине в качестве конкретного тестового пользователя (через параметр -Session) в фоновом режиме (через параметр -AsJob).Сеанс создается следующим образом:
New-PSSession -computername $myServer -credential $myCredential
Блок сценария выполняет ряд действий, кульминацией которых является запуск тестовой среды NUnit.В тестируемом коде C # записывается имя пользователя «myTestUser» (через Environment.UserName
), поэтому учетные данные, предоставленные PowerShell, должным образом принимаются.Это еще раз подтверждается Process Explorer: проверка свойств nunit-console, выполняющих пакетные тесты, показывает, что он принадлежит 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 AUTHORITY \ ANONYMOUS LOGON'
Некоторая дополнительная информация:
- Я подтвердил, что тестовый пользователь(myTestUser) имеет разрешения БД, а тест NUnit способен получить доступ к БД. Когда я запускаю тест NUnit вручную (через графический интерфейс NUnit), вошедший в систему как myTestUser, тест работает правильно, и SqlProfiler четко показывает эту активность, когда myTestUser отображается в NTUserNamecolumn.
- Та же ошибка возникает, если я работаю локально, а не на удаленной машине.
- Та же ошибка возникает, если я работаю как я на своей локальной машине (то есть без параметра -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 LOGON».Оставшиеся две строки сообщают имя пользователя «testuser», но обе сообщают об одном и том же сбое при входе в систему для соединения с БД.
То, что этот изолированный пример говорит мне, не то, что я думаю, что что-то содержит ошибки в Powershell, .NETили мой код, но есть что-то с механизмом аутентификации, которого я еще не понимаю, поскольку при указании другого компьютера или сеанса оба пути включают путь, который в некотором смысле должен иметь более надежную защиту.
2011.08.03 Обновление - Eureka!
Что ж, Мэтт правильно определил проблему double-hop в качестве виновника и CredSSP аутентификацию в качестве решения.К сожалению, как я быстро выяснил, CredSSP требует Windows 7, поэтому я решил настроить пару виртуальных машин в качестве песочницы.CredSSP, однако, был не из тех, кто легко отказался от своих секретов (по крайней мере, для меня), как я подробно описал в этом посте о ServerFault: Не удается заставить CredSSP-аутентификацию работать в PowerShell
Я наконец-то былсмог заставить аутентификацию CredSSP работать так, чтобы я мог вернуться к проблеме, которую я поставил здесь в этой теме.В качестве теста я использовал эти 3 блока скриптов, подключенных к скрипту PowerShell, который я предоставил выше:
$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.