Solved: Getting 401 Unauthorized while calling an ASMX service using windows authentication

Today I’ve spent almost the whole day to figure out why an application (COM+) couldn’t authenticate against a ASMX web service. Using my favorite networking tools Wireshark and HTTP Fiddler I saw that the credentials didn’t get included in the initial request, and no other request was made when the 401 challenge came from the web service.

The code was doing something like this:

using (client = new MyWebService())
{
    var credentials = new NetworkCredential();
    credentials.Username = ConfigurationManager.AppSettings["WSUserName"]
    credentials.Password = ConfigurationManager.AppSettings["WSPassword"]
    credentials.Domain = ConfigurationManager.AppSettings["WSDomain"]
    client.Credentials = credentials;

    // .. and the call here ..
}

That didn’t work very well. So I fiddled around with CredentialsCache (trying both “Negotiate” and “NTLM”) and using FQDN or just the server name:

var cache = new System.Net.CredentialCache();
cache.Add(new Uri("http://srt00428"), "NTLM", new NetworkCredential("SomeName", "SomePassword"));

var client = new MyWebService();
client.Credentials = cache;
// ..and the call..

That didn’t work so well either.

Then I tried to assign it directly:

var client = new MyWebService();
client.Credentials = new NetworkCredential("SomeName", "SomePassword", "MyDomain")
// ..and the call..

Didn’t work either. And out of desperation I just tried to use the username/password:

var client = new MyWebService();
client.Credentials = new NetworkCredential("SomeName", "SomePassword")
// ..and the call..

Voila! It worked. Don’t ask me why, but it does. Do note that I couldn’t get this to work:

using (client = new MyWebService())
{
    var credentials = new NetworkCredential();
    credentials.Username = ConfigurationManager.AppSettings["WSUserName"]
    credentials.Password = ConfigurationManager.AppSettings["WSPassword"]
    client.Credentials = credentials;

    // .. and the call here ..
}

The username/password HAS to be set in the NetworkCredential constructor..

My final code:

using (client = new MyWebService())
{
    var username = ConfigurationManager.AppSettings["WSUserName"]
    var password = ConfigurationManager.AppSettings["WSPassword"]
    client.Credentials = new NetworkCredential(username, password);

    // .. and the call here ..
}

  • giulio8

    but how was the authentication implemented on the service side ? btw isn’t it useless without encryption ?

    • JonasGauffin

      Server side it’s just a setting in IIS
      Windows auth is always encrypted (kerberos)?

      • giulio8

        please look at the user and password properties after you call NetworkCredential with user and psw parameters: do you get the same values you were trying to set in the example before ?

        • JonasGauffin

          That’s only in your application. It’s not sent as clear text over the network. There is however a new constructor for NetworkCredential that supports the SecureString class (so that your password is encrypted in your app too)

          • giulio8

            so you confirm that you get the same values but the setter is not working, do you? thanks

          • JonasGauffin

            sorry. misread your question. I’ve not checked.

          • giulio8

            my fault, i was unclear. it is expected that you get the same plain value and that
            ncr = new networkcredential();
            ncr.username = usr;
            ncr.password = psw;
            works exactly as
            ncr = networkcredential(usr,psw)

            Thanks and regards

          • JonasGauffin

            One would expect it to work the same. But it doesn’t. At least not when authenticating. The NetworkCredential class is a bit complex if you look at the source code.

          • giulio8

            will do.
            of course I tried the above code and my athentication process worked the same…
            I usedjust missed a “new” when posting the code…
            I used the basic authentication and
            I’m curious to read the code of that class and will check other authentication types…
            Thanks

          • JonasGauffin

            We have impersonation enabled. Don’t know if it’s because of that (i.e. we have only impersonation + windows auth in IIS). I reproduced the same problem several times to make sure that nothing else differed.

            The call goes like this:

            ASP.NET WebForms App (Impersonation+WinAuth) calls a ASMX service (with Impersonation+WinAuth). Both in the same domain.