title: Programmatically impersonate fixed windows identity for web service
body: <p>I have a web service (old web service, not WCF) and I am using IIS 7.0 to communicate to that web service.  Only Windows Authentication is enabled in IIS 7.0 (even Anonymous is disabled).  I need to be able to specify a specific windows identity within code when making the service call.  I have found many places that indicates this can be done in the config file in the following manner...</p>
  
  <pre><code>&lt;authentication mode="Windows" /&gt;
  &lt;identity impersonate="true" userName="UserName" password="P@ssw0rd" /&gt;
  </code></pre>
  
  <p>But I need to do this same thing in code.  I am sure that are many people thinking "Why would you want to do it that way".  Without going into the big long explanation the simpliest answer is because those are my requirements.</p>
  
  <p>Here is what my code looks like...</p>
  
  <pre><code>HttpTransportBindingElement transport = useHttps ? new HttpsTransportBindingElement() : new HttpTransportBindingElement();
  transport.ManualAddressing = false;
  transport.MaxBufferPoolSize = 134217728; // 128MB
  transport.MaxReceivedMessageSize = 134217728; // 128MB
  transport.AllowCookies = false;
  transport.AuthenticationScheme = AuthenticationSchemes.Negotiate;
  transport.BypassProxyOnLocal = false;
  transport.DecompressionEnabled = true;
  transport.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
  transport.KeepAliveEnabled = true;
  transport.MaxBufferSize = 134217728; // 128MB,
  transport.ProxyAuthenticationScheme = AuthenticationSchemes.Negotiate;
  transport.Realm = "";
  transport.TransferMode = TransferMode.Buffered;
  transport.UnsafeConnectionNtlmAuthentication = false;
  transport.UseDefaultWebProxy = false;
  
  TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement
  {
      MaxReadPoolSize = 64,
      MaxWritePoolSize = 16,
      MessageVersion = MessageVersion.Soap12,
      WriteEncoding = Encoding.UTF8,
      ReaderQuotas = new XmlDictionaryReaderQuotas
      {
          MaxDepth = 32,
          MaxStringContentLength = 134217728, // 128MB
          MaxArrayLength = 134217728, // 128MB
          MaxBytesPerRead = 4096,
          MaxNameTableCharCount = 16384
      }
  };
  
  CustomBinding binding = new CustomBinding();
  binding.Elements.Add(encoding);
  binding.Elements.Add(transport);
  
  ServicePointManager.Expect100Continue = false;
  
  generalSoapClient general = new generalSoapClient(binding, new EndpointAddress("http://localhost/site/ws/general.asmx"));
  NetworkCredential iisCredentials = new NetworkCredential("UserName", "P@ssw0rd");
  general.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
  general.ClientCredentials.Windows.ClientCredential = iisCredentials;
  string session = general.CreateDomainUserSessionFromInstance();
  </code></pre>
  
  <p>There is nothing defined in the .config file on the client side.  Everything is configured in code.</p>
  
  <p>My web service method looks like this (some code missing that is not related to authentication)...</p>
  
  <pre><code>[WebMethod(EnableSession = true)]
  [OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
  public string CreateDomainUserSessionFromInstance()
  {
      if(HttpContext.Current.User != null &amp;&amp; HttpContext.Current.User.Identity.IsAuthenticated)
      {
          WindowsIdentityRequest authenticationRequest = new WindowsIdentityRequest(instanceName, HttpContext.Current.User.Identity as WindowsIdentity);
          response = authManager.Login(authenticationRequest);
      }
  
      return response.SessionContext.SessionToken;
  }
  </code></pre>
  
  <p>My web.config on the server side looks like this...</p>
  
  <pre><code>&lt;system.web&gt;
      &lt;authentication mode="Windows" /&gt;
      &lt;identity impersonate="true" /&gt;
      &lt;authorization&gt;
          &lt;!--&lt;allow users="*" /&gt;--&gt;
          &lt;deny users="?" /&gt;
      &lt;/authorization&gt;
  &lt;/system.web&gt;
  
  &lt;customBinding&gt;
      &lt;binding name="textHttpBinding" receiveTimeout="00:05:00" sendTimeout="00:05:00"&gt;
        &lt;textMessageEncoding&gt;
          &lt;readerQuotas maxArrayLength="1024000000" maxStringContentLength="1024000000" /&gt;
        &lt;/textMessageEncoding&gt;
        &lt;httpTransport maxReceivedMessageSize="1024000000" maxBufferSize="1024000000" authenticationScheme="Negotiate" /&gt;
    &lt;/customBinding&gt;
  </code></pre>
  
  <p>When I have the <code>&lt;deny users="?" /&gt;</code> I get the following error..."<em>The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was ''</em>"
  Someone told me it should be <code>&lt;allow users="*" /&gt;</code> but when I do this I can get into the web service but the <code>HttpContext.Current.User.Identity.IsAuthenticated</code> is false and <code>.Name</code> is empty and what I read on the internet is that it needs to be <code>deny users="?" /&gt;</code> to deny anonymous access.</p>
  
  <p>I am new to web services and so unfortunately most of this code is greek to me.  Our web service initially allowed anonymous authentication but the requirement has changed to require windows authentication.</p>
  
  <p>I have spent several days reading numerous web sites trying to get everything configured correctly and just can't seem to find the right combination.<br>
  What am I doing wrong?  Is it something simple or am I way off base?</p>