0

I'm experiencing some odd behaviour (meaning I don't understand what's happening) and I'd like some help fixing it if possible.

We have some Dynamics 365 NAV Business Central web services exposed an secure with an SSL ceritificate, which we're accessing using some standard C# code.

We've added the SOAP proxy to an ASP .NET Webforms application and this is all working as expected.

We then declare an instance of the web service, set the credentials using a new NetworkCredential instance, and set the web service to use PreAuthenticate, then call the method on our service.

public static bool CheckServiceStatus()
{
    bool returnValue = false;
    try
    {
        svcWebServiceServer webService = new svcWebServiceServer();
        webService.Credentials = new NetworkCredential(Globals.WebServiceUsername, Globals.WebServicePassword, Globals.WebServiceDomain);
        webService.PreAuthenticate = true;
        webService.FncServiceStatus(ref returnValue);
    }
    catch (Exception ex)
    {
        LoggingFunctions.WriteMessageToDisk("CheckServiceStatus error : " + ex.Message);
    }
    return returnValue;
}

When we look at the logs for this in Fiddler, we se that the service is called twice. The first time the call is made, we get a 401 error which responds telling us we must use NTLM, the second call is then made with a longer NTLM key and the call succeeds and we get our data...

First attempt...

enter image description here

Second attempt...

enter image description here

Can anyone tell me how to make the web service call so it authenticates first time? The 401s are being picked up as a DDOS style attack and then traffic is being blocked.

I have tried changing the way the credentials are passed, but this has made no difference...

public static bool CheckServiceStatus()
{
    bool returnValue = false;
    try
    {
        svcWebServiceServer webService = new svcWebServiceServer();
        CredentialCache credCache = new CredentialCache();
        credCache.Add(new Uri(webService.Url), "NTLM", new NetworkCredential(Globals.WebServiceUsername, Globals.WebServicePassword, Globals.WebServiceDomain));
        webService.Credentials = credCache;
        webService.PreAuthenticate = true;
        webService.FncServiceStatus(ref returnValue);
    }
    catch (Exception ex)
    {
        LoggingFunctions.WriteMessageToDisk("CheckServiceStatus error : " + ex.Message);
    }
    return returnValue;
}
Karl
  • 912
  • 2
  • 16
  • 28
  • When you new up the service does it make a call? Content-Length in the first call is 0. Can you new it and pass creds in one line? – wazz Dec 08 '20 at 23:34
  • Thanks Wazz, unfortunately this doesn't work. When using PreAuthenticate, for the first time, you get 2 failures, and then a success. The first failure has the correct content length, and returns a 401 saying NTLM is required, The second attempt is made (with a content length of 0) with an NTLM value, which also returns a 401, and finally on the 3rd attempt, it passes. – Karl Dec 09 '20 at 16:52
  • 1
    I think I know why this is happening now and will post an answer shortly. – Karl Dec 09 '20 at 16:54

2 Answers2

0

As per this article - https://learn.microsoft.com/en-gb/archive/blogs/chiranth/ntlm-want-to-know-how-it-works - NTLM works in a challenge response manner.

The first time the web service is called (even if you specify NTLM in a credentialCache object), it seems as though the first request is sent anonymously.

The server then responds with a 401, and some WWW-Authenticate headers specifying that the service requires authentication details via NTLM. This is the first 401.

The client (C# application) then sends a new request that includes the NTLM header which includes an encoded value representing the Username, computername and domain.

The server passes the request on to the authenticating server which generates a challenge and this is sent back to the client, in another 401 response. This is the second 401.

Once the challenge is received by the client, it calculates a hash value based on the challenge and the password, which is sent back to the web service. The authenticating server compares this hash with its own hash, and - so long as the credentials are correct - passes authentication, and a 200 response is returned, along with the results of the web service call the client made initially.

When we add PreAuthenticate = true to our code, we simply pass the NTLM username, computername and domain up front, bypassing the first step. This reduces the number of 401s from 2 to 1.

I do not claim to be an expert in the field of authentication, but after reading the page linked above and carrying out a number of tests, this is what we have found. If anyone would like to comment/correct me, please feel free.

For completeness, we have started to investigate the "UserName" authentication method in the Dynamics 265 setup to access Dynamics NAV 2018 web services, which pass this authentication to the control to Dynamics NAV 365, which means we get no 401s. However, we are now unable to access the webservices in a browser as this uses Digest, and we seem to be unable to authenticate with the browser, and get 400 errors.

Karl
  • 912
  • 2
  • 16
  • 28
0

Maybe you had to set UseDefaultCredentials to false. This is an example of how I do it. However, I did not do a check with fiddler:

NetworkCredential cred = new NetworkCredential(Globals.WebServiceUsername, Globals.WebServicePassword, Globals.WebServiceDomain);
svcWebServiceServer webService = new svcWebServiceServer();
webService.Timeout = Globals.Timeout;
webService.Url = Globals.Url;
webService.UseDefaultCredentials = false; // <-----
webService.Credentials = cred;
Tyler2P
  • 2,324
  • 26
  • 22
  • 31