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
Другие вопросы по тегам