如何将WindowsIdentity转换为NetworkCredential?

我们如何将WindowsIdentity转换为NetworkCredential ? 我正在测试我的WCF服务以validation匿名呼叫者是否被阻止。 要做到这一点,我想做的事情如下:

 myProxy.ClientCredentials.Windows.ClientCredential = foo(WindowsIdentity.GetAnonymous()); 

其中foo是一种将WindowsIdentity转换为NetworkCredential

一般来说foo不存在。 由于NetworkCredential是WindowsIdentity的更广泛的对象。 也就是说我可以在需要WindowsIdentity的地方使用NetworkCredential,但不是相反。

原因是安全性。

NetworkCredential意味着您可以使用此标识并在另一台计算机上使用其关联的CREDENTIALS。

这意味着

  1. 您拥有用户凭据而不仅仅是其身份。
  2. 这套凭证有利于模仿,而不仅仅是本地访问。

我将假设凭据来自另一台机器(由于WCF)。 再次出于安全原因,网络凭据在进入此计算机时已转换为LocalCredential(除非我们讨论的是委托而非模拟)。 客户端计算机有权在服务器计算机上使用其凭据,仅使用服务器计算机。

如果你想让NetworkCredential退出,你需要做一些名为Delegation的事情,因为所谓的多跳问题。 这涉及到Kerberos,一个黑社会的三头邪恶的狗。 您不想处理Kerberos。

一般来说,默认情况下,WCF代理不会通过其调用发送凭据。 您通常需要设置ClientCredentials或设置

 proxy.UseDefaultCredentials = true 

通常不提供凭证,因此匿名认证。

回答我自己的问题:
无法将WindowsIdentity转换为NetworkCredential 。 要测试匿名调用方是否被阻止,请使用空会话令牌模拟当前线程,然后调用WCF服务。 注意:不要使用WindowsIdentity.GetAnonymous 。 这种方法没用(猜测它是错误实现的,从未得到纠正)。 使用空会话令牌模拟当前线程的代码(未完成error handling):

  public static class Helper { [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] private static extern IntPtr GetCurrentThread(); [DllImport("advapi32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] private static extern bool ImpersonateAnonymousToken(IntPtr handle); public static void ImpersonateAnonymousUser() { ImpersonateAnonymousToken(GetCurrentThread()); } } static string ToString(IIdentity identity) { return string.Format("{0} {1} {2}", identity.Name, identity.IsAuthenticated, identity.AuthenticationType); } static void Main(string[] args) { Console.WriteLine(ToString(WindowsIdentity.GetCurrent())); Helper.ImpersonateAnonymousUser(); Console.WriteLine(ToString(WindowsIdentity.GetCurrent())); } 

输出:

 my machine\me True NTLM NT AUTHORITY\ANONYMOUS LOGON False 

在回应Edmund的评论时,将proxy.ClientCredentials.Windows.ClientCredential设置为null将不会执行缩进 – make请求作为匿名用户。 这是我完整的测试代码及其输出:

服务代码:

 public class Service1 : IService1 { // note that if client is not authenticated, this code will never get a chance to execute // exception will happen before that // therefore there is no need to decorate this method with a // [PrincipalPermission(SecurityAction.Demand, Authenticated=true)] attribute public string GetData() { try { var identity = Thread.CurrentPrincipal.Identity; return string.Concat(identity.Name, ",", identity.IsAuthenticated, ",", identity.AuthenticationType); } catch (Exception e) { return string.Concat(e.Message, "\\r\\n", e.StackTrace); } } } 

服务配置:

                     

客户代码:

 static void MakeRequest() { try { using (var svc = new Service1Client()) { Console.WriteLine(svc.GetData()); } } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); } } static void Test3() { Console.WriteLine("using {0}", ToString(WindowsIdentity.GetCurrent())); MakeRequest(); Console.WriteLine(); Console.WriteLine("setting svc.ClientCredentials.Windows.ClientCredential to null..."); try { using (var svc = new Service1Client()) { svc.ClientCredentials.Windows.ClientCredential = null; Console.WriteLine(svc.GetData()); } } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); } Console.WriteLine(); ImpersonateAnonymousUser(); Console.WriteLine("using {0}", ToString(WindowsIdentity.GetCurrent())); MakeRequest(); Console.WriteLine(); } 

客户端配置:

                           

输出:

 using mymachine\me True Negotiate mymachine\me,True,Negotiate setting svc.ClientCredentials.Windows.ClientCredential to null... mymachine\me,True,Negotiate using NT AUTHORITY\ANONYMOUS LOGON False The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state. Server stack trace: at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout) Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage req Msg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgDa ta, Int32 type) at System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout) at System.ServiceModel.ClientBase`1.System.ServiceModel.ICommunicationObject. Close(TimeSpan timeout) at System.ServiceModel.ClientBase`1.Close() at System.ServiceModel.ClientBase`1.System.IDisposable.Dispose() at TestClient.Program.MakeRequest() 

我们有一组测试,我们使用这个帮助方法:

 public static ResponseType CallService(RequestType requestBody, NetworkCredential credential) { ResponseType response; using (var channelFactory = new ChannelFactory("BasicHttpBinding_IMyService")) { channelFactory.Credentials.Windows.ClientCredential = credential; var client = channelFactory.CreateChannel(); var request = new MyRequest() { MyService = requestBody }; response = client.MyService(request).MyResponse1; ((IClientChannel)client).Close(); channelFactory.Close(); } return response; } 

测试中的用法:

 var requestBody = GetRequestBody();//another helper method var credential = new NetworkCredential { Domain = "MyDomain", UserName = "MyUsername", Password = "MyPassword" }; var response = CallService(requestBody, credential); //Assert various user credentials var response = CallService(requestBody, null); //Assert anonymous