Задача TPL в службе WCF не может использовать правильные учетные данные безопасности IIS (соединение SQL)

У меня есть метод службы WCF, который вызывает хранимую процедуру SQL. Я разрабатываю с использованием IIS 5 (мало что могу с этим поделать, II6/7 недоступен)

Чтобы получить некоторые выгоды, я делаю несколько асинхронных вызовов для этой сохраненной процедуры, помещая вызов в задачу C # TPL.

При запуске в качестве задачи я получаю исключение SQL... «Ошибка входа в систему. Логин из ненадежного домена и не может использоваться с проверкой подлинности Windows»

Однако, если я запускаю тот же процесс без использования задачи, у меня нет проблем с подключением SQL.

Мне кажется, что учетные данные для виртуальной папки IIS (WCF) не делегируются задаче? Любые идеи, как я могу указать учетные данные для потока задач TPL, т.е. использовать то же самое, что и родитель и т. д.?

Я использую проверку подлинности Windows (sspi) и олицетворение, чтобы иметь возможность подключаться к отдельному блоку SQL.

Ваша помощь оценена.


person Ron Weston    schedule 04.04.2012    source источник
comment
вы используете проверку подлинности Windows?   -  person Aliostad    schedule 04.04.2012
comment
Я имею в виду проверку подлинности Windows для IIS.   -  person Aliostad    schedule 04.04.2012
comment
Да, я использую проверку подлинности Windows для IIS, а строка подключения SQL указывает SSPI и т. д.   -  person Ron Weston    schedule 04.04.2012
comment
Извините, SQL на другой машине?   -  person Aliostad    schedule 04.04.2012
comment
да, IIS на одном компьютере, SQL на другом. Как я уже сказал, без использования TPL соединение в порядке.   -  person Ron Weston    schedule 04.04.2012


Ответы (2)


У вас есть два варианта.

1) Настройте все ваше приложение на постоянную передачу удостоверения, используя:

<runtime>
    <alwaysFlowImpersonationPolicy enabled="true"/>
</runtime>

Побочным эффектом этого являются накладные расходы и опасность случайного выполнения некоторого непреднамеренного кода с привилегиями текущего вызывающего пользователя, а не с идентификатором приложения. Лично я бы избегал этого и выбрал № 2, где вы явно соглашаетесь.

2) Захватите WindowsIdentity перед настройкой задач TPL и явным образом олицетворяйте где вам нужно совершать звонки, используя Impersonate + WindowsImpersonationContext:

public void SomeWCFOperation()
{
    WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();

    Task.Factory.StartNew(() =>
    {
         // some unpriviledged code here


         using(WindowsImpersonationContext impersonationContext = currentIdentity.Impersonate())
         {
            // this code will execute with the priviledges of the caller
         }

         // some more unpriviledged code here
    });  
}
person Drew Marsh    schedule 06.04.2012
comment
Привет Дрю. Хороший четкий ответ, рад, что вы сразу поняли мою проблему. Я не смогу попробовать это решение до Пасхи, но как только я это сделаю, я отмечу этот вопрос как ответ. Вы должны потратить свои 50 бонусных баллов с умом, хотя я могу добавить ;-) - person Ron Weston; 07.04.2012
comment
Да, я могу подтвердить, что это работает нормально (ну вариант 2). Еще раз спасибо - person Ron Weston; 11.04.2012
comment
Хм. Вариант 1, похоже, не работает для меня (настроен через Web.config) - работает только вариант 2, но я надеялся избежать распространения удостоверения через несколько уровней потоковой передачи. - person lesscode; 12.07.2012
comment
Я вижу, что происходит. В моем случае я размещаю WAS-сервис WCF. Конфигурация web.config ‹runtime› не вступает в силу — мне нужно либо отредактировать глобальный aspnet.config, либо установить собственный CLRConfigFile в моем пуле приложений. - person lesscode; 12.07.2012
comment
Да, CLRConfigFile в AppPool должен вам помочь. - person Drew Marsh; 12.07.2012

В качестве другого обходного пути вы можете создать расширения для TPL следующим образом:

public static class TaskFactoryExtensions
{
    public static Task StartNewImpersonated(this TaskFactory taskFactory, Action action)
    {
        var identity = WindowsIdentity.GetCurrent();
        return taskFactory.StartNew(() =>
        {
            using (identity.Impersonate()) 
            {
                action();
            }
        });
    }

    public static Task<TResult> StartNewImpersonated<TResult>(this TaskFactory taskFactory, Func<TResult> function)
    {
        var identity = WindowsIdentity.GetCurrent();
        return taskFactory.StartNew<TResult>(() =>
        {
            using (identity.Impersonate())
            {
                return function();
            }
        });
    }
}

Затем вы должны вызывать эти новые методы вместо стандартных методов StartNew.

Недостатком этого является то, что существует множество методов для переопределения.

person Andy Cohen    schedule 30.08.2012