WCF служба двойного подражания?
Моя настройка немного сложна, поэтому позвольте мне сначала пройтись по этому вопросу.
У нас есть веб-сервис WCF, который получает данные из различных источников через несколько различных API и возвращает эти данные клиенту. Запрашиваемая защита заключается в том, что она выполняется через HTTPS(работает). Стандарт IIS предусматривает, что пул приложений должен быть настроен на использование основной учетной записи сетевой службы IIS и что должно использоваться олицетворение.net.
Моя проблема заключается в том, что веб-служба всегда должна работать под идентификатором процесса AD независимо от того, кто ее вызывает, но также должна проверять группы AD, в которых находится вызывающая сторона, чтобы определить, какие функции доступны. Теперь я могу настроить мой web.config для использования, и этот вид работы заставляет его всегда работать как Blah, но тогда я не знаю, как заставить его выдавать себя за другого / проверять вызывающего пользователя, чтобы увидеть, к каким функциям у него тоже есть доступ.
** edit: забыл упомянуть, что вызывающий клиент должен иметь возможность передавать UN/PASS вместо его токена Windows. Служба wcf должна проверить действительные AD UN и PASS, а также опросить, по каким группам она работает.
1 ответ
Звучит так, как ты хочешь HostingEnvironment.Impersonate
Пример:
using (var imp = HostingEnvironment.Impersonate())
{
// code now executes in the context of the authenticated user,
// rather than the service account
}
Это работает фантастически, к сожалению, стандарт здесь заключается в том, чтобы не использовать пулы приложений, поскольку управление паролями для них проще, если каждая команда поддерживает их в актуальном состоянии, помещая их в web.config.
Ну, это кажется нелогичным, но я сталкиваюсь с худшей политикой в свое время, так что я вряд ли буду судить.;)
Как я уже упоминал в своем комментарии, существуют перегрузки I mpersonate, которые позволят вам выдавать себя за произвольную учетную запись. Чтобы сделать это, вы должны получить маркер идентификации Windows для этого пользователя, и это нетривиально, и, насколько я знаю, это не то, что вы можете сделать на 100% в управляемом коде. Вам нужно будет использовать неуправляемый код и знать имя пользователя и пароль для олицетворенной учетной записи в вашем приложении. Это гораздо менее безопасно, чем просто установить учетную запись в качестве идентификатора пула приложений, если вы когда-нибудь захотите поспорить с сетевым архитектором BTW. Просто патроны для тебя.
Во всяком случае, вот пример кода, который я адаптировал из интернета:
#region native imports.
public const int Logon_LogonTypeInteractive = 2;
public const int Logon_ProviderDefault = 0;
public const int Duplicate_ImpersonationLevelImpersonate = 2;
[DllImport("advapi32.dll")]
public static extern bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
#endregion native imports.
#region elsewhere...
public IntPtr GetWindowsTokenForImpersonation(string username, string password, string domain)
{
IntPtr loginToken = IntPtr.Zero;
IntPtr workingToken = IntPtr.Zero;
bool success
if(!RevertToSelf())
{
return IntPtr.Zero;
// failed to eliminate any existing impersonations. This block may not be necessary depending on your code
}
if(!LogonUserA(username, domain, password, Logon_LogonTypeInteractive, Logon_ProviderDefault, ref loginToken))
{
return IntPtr.Zero;
// failed to log in the user
}
if(!DuplicateToken(loginToken, Duplicate_ImpersonationLevelImpersonate, ref workingToken)
{
if(loginToken != IntPtr.Zero)
{
CloseHandle(loginToken);
}
return IntPtr.Zero;
// failed to get a working impersonation token
}
CloseHandle(loginToken);
return workingToken; // NOTE: You must dispose this token manually using CloseHandle after impersonation is complete.
}
#endregion elsewhere
#region where you want to impersonate
var token = GetWindowsTokenForImpersonation(username, password, domain);
if(token != IntPtr.Zero)
{
using(var imp = HostingEnvironment.Impersonate(token))
{
// code here executes under impersonation
}
CloseHandle(token);
}
#endregion