ASMX: Service reference API invocation fails with MessageSecurityException

Problem statement
1. Web service application (ASMX) is hosted on Windows server 2008 R2 (SQL service). The service application can also be hosted on IIS. The service is available over http.
2. From client machine and a console application, the web reference method call succeeds.
3. From the same client machine and console application, the service reference method call fails with exception System.ServiceModel.Security.MessageSecurityException {"The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'."}.
4. What is the solution to this failure?

Assessment
1. The ASMX is configured with Windows authentication (NTLM) on server.
2. By default, an application is hosted on windows server other than IIS, it picks NTLM protocol.
3. Service application is configured for Impersonation as well.

Actions
1. Browse the web service and inspect the headers in fiddler. It will show proper NTLM token.
2. Call the method with web reference from application. Fiddler shows proper same NTLM token, because it runs with the logged in user.
3. Call the method with service reference from application. Fiddler shows the same NTLM token, but communication breaks.
4. Web reference method call has no issues because it follows the ASP.NET pipeline, whereas service method call has to pass the system.serviceModel pipeline first and then the ASP.NET pipeline comes in picture (if looked from client side perspective).

Solution for service reference call failure
The difference over here is to set is to set the allowed impersonation level.

App.config

     <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="soapBinding">
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Ntlm" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="myserver/MyServiceApplication/Service1.asmx"
                binding="basicHttpBinding" bindingConfiguration="soapBinding"
                contract="ServiceReference1.MyServiceSoap" name="myServiceSoap" />
        </client>
    </system.serviceModel>

Program.cs

             var client = new MyServiceSoapClient();

            // the server process can impersonate the client’s security context on its local system
            client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

            // invoke web method
            var res = client.MyMethod(new myMethodRequest { Property1 = "input 1", Property2 = "input 2" });

            client.Close();

            Console.WriteLine("Operation completed");
            Console.ReadLine();

 

 

 

Hope this helps - happy coding!