Answering my question:
Converting a WindowsIdentity to NetworkCredential not possible. To check if anonymous subscribers are blocked, issue the current stream from the session zero token , and then call the WCF service. Note: do not use WindowsIdentity.GetAnonymous . This method is useless (suppose it was improperly implemented and has never been fixed). Code to impersonate the current thread with a zero session token (error handling is not performed):
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())); }
Output:
my machine\me True NTLM NT AUTHORITY\ANONYMOUS LOGON False
In response to Edmund's comment, setting proxy.ClientCredentials.Windows.ClientCredential to null will not do the indentation of making the request an anonymous user. Here is my complete test code and its output:
Service Code:
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); } } }
Service Configuration:
<services> <service name="WcfService1.Service1"> <host> <baseAddresses> <add baseAddress="http://mymachine/Service1/" /> </baseAddresses> </host> <endpoint address="Service1" binding ="customBinding" bindingConfiguration="myHttpBinding" contract="WcfService1.IService1"> </endpoint> </service> </services> <bindings> <customBinding> <binding name="myHttpBinding"> <reliableSession/> <binaryMessageEncoding /> <httpTransport maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" authenticationScheme="IntegratedWindowsAuthentication" /> </binding> </customBinding> </bindings>
Client Code:
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(); }
Client Configuration:
<bindings> <customBinding> <binding name="CustomBinding_IService1"> <reliableSession /> <binaryMessageEncoding /> <httpTransport authenticationScheme="Negotiate" /> </binding> </customBinding> </bindings> <client> <endpoint address="mymachine/Service1/Service1.svc/Service1" binding="customBinding" bindingConfiguration="CustomBinding_IService1" contract="ServiceReference1.IService1" name="CustomBinding_IService1"> <identity> <servicePrincipalName value="host/mymachine" /> </identity> </endpoint> </client> <behaviors> <endpointBehaviors> <behavior name="ImpersonationBehavior"> <clientCredentials> <windows allowedImpersonationLevel="Identification"/> </clientCredentials> </behavior> </endpointBehaviors> </behaviors>
Output:
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()