title: Asmx web service basic authentication
body: <p>I want to implement basic authentication using username and password validation in my <strong>asmx</strong> web service.<br>
  <strong>I don't want to use WCF and I know this is not secure way</strong>, but I need to use basic authentication without using https.  </p>
  
  <p>My web service is like this:</p>
  
  <pre class="lang-c# prettyprint-override"><code>[WebService(Namespace = "http://www.mywebsite.com/")]
  public class Service1
  {
      [WebMethod]
      public string HelloWorld()
      {
          return "Hello world";
      }
  }
  </code></pre>
  
  <p>And I use this custom HttpModule:</p>
  
  <pre class="lang-c# prettyprint-override"><code>public class BasicAuthHttpModule : IHttpModule
  {
      void IHttpModule.Init(HttpApplication context)
      {
          context.AuthenticateRequest += new EventHandler(OnAuthenticateRequest);
      }
  
      void OnAuthenticateRequest(object sender, EventArgs e)
      {
          string header = HttpContext.Current.Request.Headers["Authorization"];
  
          if (header != null &amp;&amp; header.StartsWith("Basic"))  //if has header
          {
              string encodedUserPass = header.Substring(6).Trim();  //remove the "Basic"
              Encoding encoding = Encoding.GetEncoding("iso-8859-1");
              string userPass = encoding.GetString(Convert.FromBase64String(encodedUserPass));
              string[] credentials = userPass.Split(':');
              string username = credentials[0];
              string password = credentials[1];
  
              if(!MyUserValidator.Validate(username, password))
              {
                  HttpContext.Current.Response.StatusCode = 401;
                  HttpContext.Current.Response.End();
              }
          }
          else
          {
              //send request header for the 1st round
              HttpContext context = HttpContext.Current;
              context.Response.StatusCode = 401;
              context.Response.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", string.Empty));
          }
      }
  
      void IHttpModule.Dispose()
      {
      }
  }
  </code></pre>
  
  <p>And in the web.config I use this:</p>
  
  <pre class="lang-xml prettyprint-override"><code>&lt;?xml version="1.0"?&gt;
  &lt;configuration&gt;
      &lt;appSettings/&gt;
      &lt;connectionStrings/&gt;
      &lt;system.web&gt;
          &lt;customErrors mode="Off" /&gt;
          &lt;compilation debug="true" targetFramework="4.0"/&gt;
          &lt;authentication mode="None"/&gt;
      &lt;/system.web&gt;
      &lt;system.webServer&gt;
          &lt;modules runAllManagedModulesForAllRequests="true"&gt;
              &lt;add name="BasicAuthHttpModule"
                   type="AuthService.BasicAuthHttpModule, AuthService" /&gt;
          &lt;/modules&gt;
      &lt;/system.webServer&gt;
  &lt;/configuration&gt;    
  </code></pre>
  
  <p>The calling code is:</p>
  
  <pre class="lang-c# prettyprint-override"><code>static void Main(string[] args)
  {
      var proxy = new Service1.Service1()
                      {
                          Credentials = new NetworkCredential("user1", "p@ssw0rd"),
                          PreAuthenticate = true
                      };
      try
      {
          var result = proxy.HelloWorld();
          Console.WriteLine(result);
      }
      catch (Exception e)
      {
          Console.WriteLine(e.Message);
      }
      Console.ReadKey();
  }
  </code></pre>
  
  <p>when I use this web service, the service asks for basic authentication but <code>header</code> variable in the <code>OnAuthenticateRequest</code> method always is null and     <code>MyUserValidator.Validate()</code> never run.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>The fiddler results:</p>
  
  <pre><code>POST http://www.mywebsite.com/Service1.asmx HTTP/1.1
  User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.4927)
  VsDebuggerCausalityData: uIDPo+drc57U77xGu/ZaOdYvw6IAAAAA8AjKQNpkV06FEWDEs2Oja2C+h3kM7dlDvnFfE1VlIIIACQAA
  Content-Type: text/xml; charset=utf-8
  SOAPAction: "http://www.mywebsite.com/HelloWorld"
  Host: www.mywebsite.com
  Content-Length: 291
  Expect: 100-continue
  Connection: Keep-Alive
  
  &lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;soap:Body&gt;&lt;HelloWorld xmlns="http://www.mywebsite.com/" /&gt;&lt;/soap:Body&gt;&lt;/soap:Envelope&gt;
  HTTP/1.1 401 Unauthorized
  Cache-Control: private
  Content-Type: text/html
  Server: Microsoft-IIS/7.5
  WWW-Authenticate: Basic realm=""
  X-AspNet-Version: 4.0.30319
  WWW-Authenticate: Basic realm="www.mywebsite.com"
  X-Powered-By: ASP.NET
  Date: Sun, 03 Jun 2012 07:14:40 GMT
  Content-Length: 1293
  ------------------------------------------------------------------
  
  POST http://www.mywebsite.com/Service1.asmx HTTP/1.1
  User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.4927)
  VsDebuggerCausalityData: uIDPo+drc57U77xGu/ZaOdYvw6IAAAAA8AjKQNpkV06FEWDEs2Oja2C+h3kM7dlDvnFfE1VlIIIACQAA
  Content-Type: text/xml; charset=utf-8
  SOAPAction: "http://www.mywebsite.com/HelloWorld"
  Authorization: Basic dXNlcjE6cEBzc3cwcmQ=
  Host: www.mywebsite.com
  Content-Length: 291
  Expect: 100-continue
  
  &lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;soap:Body&gt;&lt;HelloWorld xmlns="http://www.mywebsite.com/" /&gt;&lt;/soap:Body&gt;&lt;/soap:Envelope&gt;
  HTTP/1.1 401 Unauthorized
  Content-Type: text/html
  Server: Microsoft-IIS/7.5
  WWW-Authenticate: Basic realm="www.mywebsite.com"
  X-Powered-By: ASP.NET
  Date: Sun, 03 Jun 2012 07:14:41 GMT
  Content-Length: 1293
  ------------------------------------------------------------------
  </code></pre>