2012-03-21 101 views
4

我的设置有点复杂,所以让我先讲解一下。WCF服务双重模仿?

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

我的问题是,Web服务应该始终在AD进程ID下运行,而不管是谁调用它,但它也应该检查调用者所在的AD组以确定哪些功能可以访问。现在我可以设置我的web.config来使用,并且这种工作使它始终以Blah的形式运行,但是我不知道如何也让它模拟/检查调用用户以查看他们有权访问哪些功能。

**编辑:忘记提及调用客户端应该能够通过一个UN/PASS而不是它的Windows令牌。 WCF服务应请验证是否它是一个有效的AD联合国和PASS以及调查哪些群体是在

回答

3

这听起来像你想HostingEnvironment.Impersonate

例:

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

这工作充满了想象,不幸的是,这里的标准是不使用应用程序池,因为密码管理对于他们来说更容易,只要其在每个团队中通过将其置于web中而使其保持最新即可。

那么,这似乎是违反直觉的,但我在我的日子遇到了更糟的政策,所以我很难判断。 ;)

正如我在我的评论中提到的那样,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 
+0

我觉得我的帖子可能是混乱的。应用程序池ID只是基本的IIS帐户。我想要始终以“Domain \ Serviceaccount1”的身份运行应用程序的进程ID,调用者ID是“Domain \ User”。 wcf服务应模拟“Domain \ Serviceaccount1”运行任何功能,但应检查“域\用户”以确保用户在正确的组中运行这些功能。实际的应用程序池ID不应该用于任何事情。 – OPcorki 2012-03-21 18:05:44

+0

为什么不将Serviceaccount1设置为应用程序池ID?也就是说,Impersonate的重载允许您模拟特定的帐户。 – Randolpho 2012-03-21 18:26:30

+0

奇怪的是,这里的标准是不使用应用程序池,因为密码管理对于他们来说更容易,如果其在每个团队中通过将其放在web.config中来更新它们 – OPcorki 2012-03-21 18:29:21