HttpClient receives 401 Response using NTLM authentication - c#

I have a C# Windows application running on .NET 4.6.1. It is posting a SOAP message to a server using NTLM authentication. It is expecting a 200 response, but receives the 401 response instead. Here is the code:
HttpClientHandler handler = new HttpClientHandler
{
Credentials = CredentialManager.GetCredentials();
};
HttpClient client = new HttpClient(handler);
using (HttpResponseMessage response = await client.PostAsync(uri, soapMessage, CancelToken))
{
string soapResponse = await response.Content.ReadAsStringAsync();
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
Parse(soapResponse);
}
}
I know that there is always a 401 response sent in order to retrieve the credentials, but I thought that the HttpResponse was supposed to contain the final response, in this case a 200 message. However, the response.StatusCode is always the 401 Unauthorized message, even though the developer on the server side assures me that immediately after the 401 message, a 200 message is sent. How can I get the 200 response and ignore the 401 response?

Related

http response is 500 on code parameter request

This is a http request to the https://auth.monday.com/oauth2/authorize endpoint on asp.net 6. It should get the code parameter from that endpoint but it's returning a 500 response with html for some reason. This is part of my code grant flow because the API has oauth2.0.
public async Task<string> GetCode(string clientId, string redirect_uri)
{
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, $"https://auth.monday.com/oauth2/authorize{clientId}");
string json =
JsonSerializer.Serialize(
new
{
query = "code"
}
);
request.Content = new StringContent(json,
Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var responseText = await response.Content.ReadAsStringAsync();
return responseText;
}
Are you missing a / in your endpoint by any chance? Should it not be https://auth.monday.com/oauth2/authorize/{clientId}?
HTTP 500 is an internal server error, this means that the server was unable to handle your request properly. If you have access to the server then I would look there as to why it was unable to handle your request. I don't see anything wrong in your request.

I am getting StatusCode: 401 "Unauthorized" in a HttpClient.PostAsync (C#)

I am trying to use an Api Rest (IGDB) making an Http Post Request with HttpClient; this request needs to have a key and a body. I am providing the key in HttpClient.DefaultRequestHeaders.Authorization, but I am getting a 401 status code, I know that the key works because I have used it in Postman and It worked fine, so I must be implementing it wrong.
My code:
private async Task<string> ConsumeApi()
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Key Name", "Key Value");
//Makes the client request only Json data
//client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("aplication/json"));
string theUri = "https://api-v3.igdb.com/games";
var stringcontent = new StringContent("fields name", UnicodeEncoding.UTF8,"application/json");
var response = await client.PostAsync("https://api-v3.igdb.com/games", stringcontent);
return response.ToString();
}
And these are Postman pictures of what I am trying to implement (works fine):
AuthenticationHeaderValue
is not setting a header but is an authorization header. Set a normal header value, not one prefixed with Authentication.

404 when accessing Design Automation API v3 through HttpClient

Running calls to the Design Automation API in Postman works just fine but when I try to make the same calls in C# using HttpClient they fail with a 404 that seems to actually hide an authentication error:
{
"developerMessage":"The requested resource does not exist.",
"userMessage":"",
"errorCode":"ERR-002",
"more info":"http://developer.api.autodesk.com/documentation/v1/errors/err-002"
}
That link leads to an authentication error:
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>1F52E60A45AEF429</RequestId>
<HostId>
[ Some base64 ]
</HostId>
</Error>
I'm following examples for how to use HttpClient, but I may be missing something. I successfully get the access token, run
var client = new HttpClient
{
BaseAddress = new Uri("https://developer.api.autodesk.com/da/us-east")
};
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue(TokenType, AccessToken);
then
var result = await client.GetAsync("/v3/forgeapps/me");
and the above json is the result's content. I use the same access token in Postman and it works.
I would wrap up the endpoint, headers, and httpmethod in the HttpRequestMessage. Then send it and assign it to HttpResponseMessage.
var client = new HttpClient
{
BaseAddress = new Uri("https://developer.api.autodesk.com/da/us-east/")
};
//throw the endpoint and HttpMethod here. Could also be HttpMethod.Post/Put/Delete (for your future reference)
var request = new HttpRequestMessage(HttpMethod.Get, "v3/forgeapps/me");
//also maybe try throwing the headers in with the request instead of the client
request.Headers.Add(TokenType, AccessToken);
// send the request, assign to response
HttpResponseMessage response = await client.SendAsync(request);
//then, we can grab the data through the Content
string result = await response.Content.ReadAsStringAsync();

Random 401 Unauthorized errors using HttpClient

I am using HttpClient to invoke a Web Api REST endpoint and once in a while I see a random 401 Unauthorized Status.
Here is my HttpClient wrapper that was created for re usability purposes. I have modified it to keep it simple for this post without modifying the core parts.
public class HttpHelper
{
public const string JsonContentType = "application/json";
public T PostAsJsonObject<T>(string uri, T t) where T : class
{
using (HttpResponseMessage response = PostJsonHttpRequest(uri, JsonContentType, t))
{
response.EnsureSuccessStatusCode();
return response.Content.ReadAsAsync<T>().Result;
}
}
private HttpResponseMessage PostJsonHttpRequest<T>(string uri, string contentType, T content) where T : class
{
if (String.IsNullOrEmpty(uri))
{
throw new ArgumentNullException("uri");
}
HttpResponseMessage response = CreateHttpClient(contentType).PostAsJsonAsync(uri, content).Result;
return response;
}
private HttpClient CreateHttpClient(string contentType)
{
var credentials = new NetworkCredential("srvuser", "somepwd", "somedomain");
return new HttpClient(new HttpClientHandler { Credentials = credentials, PreAuthenticate = true });
}
}
Here is how I am invoking it.
var httpHelper = new HttpHelper();
var response = httpHelper.PostAsJsonObject("https://xyz.pvt/inventory/api/orders", "234");
Most of the time it works fine, but once in a while I get 401 Unauthorized error. I am trying to figure out what might be causing it.
System.Net.Http.HttpRequestException: Response status code does not
indicate success: 401 (Unauthorized). at
System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() at
HttpHelper.PostAsJsonObject[T](String uri, T t)
I looked at asp.net logs, and found a strange pattern. Most of the time, I see pair of entries (401 followed by 200 OK) such as
2017-02-09 12:04:13 104.68.45.152 POST /inventory/api/orders/ - 80 - 132.64.78.120 HTTP/1.1 - 401 2 5 764
2017-02-09 12:04:16 104.68.45.152 POST /inventory/api/orders/ - 80 somedomain\srvusr 132.64.78.120 HTTP/1.1 - 200 0 0 2917
2017-02-09 12:04:16 104.68.45.152 POST /inventory/api/orders/ - 80 - 132.64.78.120 HTTP/1.1 - 401 2 5 0
2017-02-09 12:04:19 104.68.45.152 POST /inventory/api/orders/ - 80 somedomain\srvusr 132.64.78.120 HTTP/1.1 - 200 0 0 2230
But occasionally I just see 401
2017-02-09 12:14:04 104.68.45.152 POST /inventory/api/orders/ - 80 - 132.64.78.120 HTTP/1.1 - 401 2 5 0
REST api is implemented using ASP.NET Web Api 2 running on .NET 4.6.1 and in IIS 7.5, it is setup with just Windows Authentication.
Not sure what is causing the authentication to fail once in a while.
UPDATE:
Here is the new code that I wrote using async await pattern.
public class HttpHelper
{
public const string JsonContentType = "application/json";
private HttpClient CreateHttpClient(string url, string contentType)
{
var handler = new HttpClientHandler
{
Credentials = new CredentialCache { { new Uri(url), "NTLM", new NetworkCredential("srvuser", "somepwd", "somedomain") } },
PreAuthenticate = true
};
var httpClient = new HttpClient(handler);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
return httpClient;
}
private async Task<HttpResponseMessage> PostJsonHttpRequestAsync<T>(string url, string contentType, T content) where T : class
{
if (string.IsNullOrEmpty(url))
{
var exception = new ArgumentNullException("url");
throw exception;
}
var response = await CreateHttpClient(url, contentType).PostAsJsonAsync(url, content);
return response;
}
public async Task<T> PostAsJsonObjectAsync<T>(string uri, T t) where T : class
{
using (var response = await PostJsonHttpRequestAsync(uri, JsonContentType, t))
{
return await response.Content.ReadAsAsync<T>(new[]
{
new JsonMediaTypeFormatter
{
SerializerSettings = { NullValueHandling = NullValueHandling.Ignore, TypeNameHandling = TypeNameHandling.Auto }
}
}.AsEnumerable());
}
}
}
Here is how I am finally invoking it.
static class TestMe
{
static void Main()
{
var httpHelper = new HttpHelper();
var responseTask = httpHelper.PostAsJsonObjectAsync("https://xyz.pvt/inventory/api/orders", "234");
responseTask.Wait(120000);
var response = responseTask.Result;
Console.WriteLine(response);
}
}
Even now I see same problem. Still getting random 401 Unauthorized errors.
UPDATE 2
I did some more investigation and found that these mysterious 401 errors are coming from IIS. When ever these mysterious 401 error occurs, IIS log has a corresponding 401 error entry, but in this case the request never reaches asp.net pipeline. As if for some reason the request is bounced back by IIS with 401 error.
Without going into too much in depth, I know that windows authentication in IIS uses 2 requests to manage authentication based on how the HttpClient is configured. So a successful authentication request will have a 401.2 followed by 200 OK. It is what happening most of the time. Occasionally thou I notice there is a 401.2, followed by just 401. The same request upon retry attempt goes thru fine (401.2 followed by 200 OK).
Really appreciate if anyone have some insight into this issue and a potential resolution to it.
Are you certain that your code is even the problem? I don't know the details of your situation, but it's possible the web server is sometimes sending you back 401 responses for no good reason.
Here's something you could do to test this theory: run two (or more) instances of your program simultaneously, ideally on different machines. Wait until you get the 401 errors. If all instances of your code start receiving the 401 errors at the same time, then it's almost certainly a problem on the web server.

C# HttpClient 303 SeeOther bug

HttpClient automatically handles 303 (SeeOther) as described in https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.118).aspx
SeeOther automatically redirects the client to the URI specified in
the Location header as the result of a POST. The request to the
resource specified by the Location header will be made with a GET.
The same behavior seems to happen on GET requests, but the call fails as if my Authorization header was missing.
I set the header using
public void SetOauthToken(String key, String token)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(key, token);
}
I am able to fix the error by intercepting the 303 and calling the URI from Location header by hand.
For example I change
public async Task<T> GetXML<T>(String url)
{
using (HttpResponseMessage response = await client.GetAsync(url))
{
string result = await response.Content.ReadAsStringAsync();
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(new StringReader(result));
}
}
to
public async Task<T> GetXML<T>(String url)
{
using (HttpResponseMessage response = await client.GetAsync(url))
{
if (response.StatusCode == HttpStatusCode.SeeOther)
{
return await GetXML<T>(response.Headers.Location.ToString());
}
else
{
string result = await response.Content.ReadAsStringAsync();
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(new StringReader(result));
}
}
}
and it fixes the bug.
When examining the redirect request everything seems fine. The redirect call works from Postman.
Any idea why is this happening?
First, don't always believe the http status responses. Websites often change the values to make it harder for hackers to get access to the server. When a Http connection is made a negotiation takes place between client and server using the http headers. The negotiation attempts to get a common mode for the transfer. For example a server may be designed to work in English, French, and German. The client includes English in the header so the client will then connect to the English webpages. So you leaving out the AuthenticationHeaderValue is not a bug, but a line of code that is required. A IE webpage is more robust than the Net Http Client and sends more default headers. If you used a sniffer like wireshark or fiddler and compared the headers using an IE and you application you would see the differences.

Categories

Resources