WCF服务双重模拟

本文关键字:模拟 服务 WCF | 更新日期: 2023-09-27 18:28:46

我的设置有点复杂,所以让我先介绍一下。

我们有一个WCF web服务,它通过几个不同的API从各种来源获取数据,并将数据返回给客户端。请求的安全性是通过HTTPS完成的(工作)IIS标准是应用程序池必须设置为使用基本IIS网络服务帐户,并且应使用.net模拟。

我的问题是,无论是谁调用web服务,它都应该始终在AD进程ID下运行,但它还应该检查调用方所在的AD组,以确定哪些功能是可访问的。现在我可以将web.config设置为使用,这种方法可以使它始终以Blah的形式运行,但我不知道如何使它模拟/检查调用用户,以查看他们也可以访问哪些函数。

**edit:忘了提到主叫客户端应该能够传递UN/pass,而不仅仅是其windows令牌。wcf服务应验证其有效的AD UN和PASS,并轮询其所在的组。

WCF服务双重模拟

听起来你想要HostingEnvironment.Impersonate

示例:

using (var imp = HostingEnvironment.Impersonate())
{
    // code now executes in the context of the authenticated user, 
    // rather than the service account
}

这非常有效,不幸的是,这里的标准是不使用应用程序池,因为如果每个团队都可以通过将其放在web.config 中来保持最新,密码管理对他们来说更容易

嗯,这似乎有违直觉,但我这一天遇到过更糟糕的政策,所以我很难做出判断。)

正如我在评论中提到的,有一些Impersonate的重载将允许您模拟任意帐户。为了做到这一点,您必须获得该用户的windows标识令牌,这是非常重要的,而且据我所知,这不是您可以在托管代码中100%做到的。您必须使用非托管代码,并且必须知道应用程序中模拟帐户的用户名和密码。如果你想与你的网络架构师BTW争论这一点,这远不如简单地将帐户设置为应用程序池ID安全。

总之,下面是我从互联网上改编的一些示例代码:

#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