First of all, let me say that I am not used to the HttpClient API, REST protocol nor Windows Authentication. It is possible I want to do something definitely impossible.
From a WPF application configured like this (don't know if it is relevent):
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
I am writing a call to a REST Web Service through HttpClient. I want to provide to the WS the currently logged in user credentials in order to check on the WS side if he can actually call it.
I have read plenty of examples on the internet and I though I just had to provide to the HttpClient a HttpClientHandler configured like this to do so:
var handler = new HttpClientHandler
{
UseDefaultCredentials = true
};
_client = new HttpClient(handler, true);
var response = await _client.GetAsync(concreteUrl);
I also tried a lots of combinations with some other properties I found on the internet:
PreAuthenticate = true
Credentials = CredentialCache.DefaultCredentials
But no matter the combinations tried to configure the handler, with fiddler, when I look at the request, the header is desperately empty:
GET http://my.domain/url/ HTTP/1.1
Host: my.domain
Connection: Keep-Alive
In the Auth tab:
No Proxy-Authorization Header is present.
No Authorization Header is present.
The WS is being developed in PHP by the way, and the client is running under .NET 4.5.2.
Is this even possible? Otherwise, how could I authenticate the user on the WS through HttpClient requests?
Related
I wanna send request to external API through the HttpClient from my own API in c#.
I am using dot net 5 and basic authentication.
Here is my code:
var client = new HttpClient
{
BaseAddress = new Uri(baseUrl)
};
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Put, "apiUrl");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var param = JsonConvert.SerializeObject(new
{
param1="",
param2=""
});
requestMessage.Content = new StringContent(param, Encoding.UTF8, "application/json");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{pass}")));
HttpResponseMessage response = await client.SendAsync(requestMessage);
Usually, I send http request like this.
but now I have some problem.
After line HttpResponseMessage response = await client.SendAsync(requestMessage); authorization header removed from my request header and I got UnAuthorized http error.
I know that when redirection occurs, authorization header removed for security reason. Also I'm not sure about redirect in external API.
I add the HttpClientHandler with AllowAutoRedirect = false to my HttpClient
var handler = new HttpClientHandler()
{
AllowAutoRedirect = false,
};
var client = new HttpClient (handler)
{
BaseAddress = new Uri(baseUrl)
};
Now I got Redirect error 301(Permanently moved).
I decided to test the code in Postman. By default, when I call API in Postman, I got http error 405 method not allowed and error detail like this:
{
"detail": "Method "GET" not allowed."}
External API method is PUT. but here I got GET Error.
I tried many options in postman and finally I find the option in Postman:
When I toggle it on, external API work's properly.
Also I test it with Insomnia and it's work properly.
Does it related to my code or dot net 5 or what other thing in my code or it's related to external API?
If it's related to my code, How can I solve the error?
If error related to external API, why Postman and Insomnia response is ok?
External API has Core Policy for specific domain and I send request from other domain.
All I Know is that the CORS policy applied in browser. not in Postman, Insomnia or C# Code.
What about CORS? Does it related to CORS? if Yes, what shall I do?
I will be grateful for your answer.
Update
I detect WWW-Authenticate: JWT realm="api" in the response header.
What exactly is it? and what shall I do?
I find out the problem. It's really Ridiculous.
When I use URL like www.abc.com/api/something the request gets 301 error and postman sends another request like www.abc.com/api/something/. The difference is just / at the end of request.
I tried new URL in postman and first request got ok.
Also I tried URL in my C# code and again its ok.
But i could not understand why.
Thanks a lot dear #pharaz-fadaei
You are right about the removal of authorization headers after redirects. But keep in mind that this behavior is part of the design of the HttpClient in C#. Postman and Insomnia may have different mechanisms to send the authorization headers on each consecutive request that is caused by redirects. The option that you enabled in Postman will make it use the original HTTP method you specified (PUT) as the HTTP method to send further requests based on the redirect messages (Postman uses GET method by default on requests instructed by redirect messages).
The fact that you see a 301 shows that a redirection is required. You can check Location header value in response.Headers to see the real location and send your requests with the authorization headers to that endpoint directly. If I were you I wouldn't use the new location directly because the original endpoint is what you were given by the authors of the API. Instead I would programmatically send the request to the original endpoint and resend the request on 301 codes to the new Location (use PUT method due to the behavior of Postman) until you get the result. This answer can give you some ideas: https://stackoverflow.com/a/42566541/1539231
Since you see WWW-Authenticate: JWT realm="api" header, the external API is required a JWT token authentication, not basic authentication. I think first you might need to check external api's documentation.
I have some service, which is SOAP API placed on Windows Server machine protected by Kerberos authentication. I would like to consume this API using .NET Core.
For now I was using some WCF client with basic authentication. So I was using some interface obtained from wsdl and after providing some credentials it was fine. Now I have to switch to Kerberos.
On the server SPN's are configured and I got a keytab file with principals.
As far as I know it is not such a simple case, so I have prepared some shared library in C++ to obtain the negotiate header value (it uses principals from proper keytab). I ve included this library in .net core project using DllImport and everything works fine. I m able to connect to the API, get the negotiate header, as well as obtain the ticket using kinit
kinit -V HTTP/test.test.com#test.com works fine.
header
When I already have the Negotiate header value, I would like to make simple POST request (using httpClient) with proper header value (ticket), but always I got 401 Unaithorized.
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("http://example.com/");
httpClient.DefaultRequestHeaders.Add("Accept", "some-type");
httpClient.DefaultRequestHeaders.Add("Content-Type", "some-type");
httpClient.DefaultRequestHeaders.Add("Authorization", "Negotiate XYZAA....."
// ...
}
As a body I send simple SOAP envelope which is fine.
Should I store something more just after obtaining a ticket, or it is just enough to add this ticket to each outgoing request as shown above?
I am trying to make a GET request to a RESTful service but the .NET HttpClient is receiving a timeout, but via Postman this returns an expected response (an error response, since I'm not yet "logged in") within seconds.
What I've tried:
I have checked the URLs are the same and they are.
I thought perhaps Postman's automagical headers are the issue, but after setting these in the HttpClient I still receive a timeout.
If I increase the timeout on the HttpClient I still get a timeout from the server ((504) Gateway Timeout).
Client = new HttpClient(new HttpClientHandler()
{
AutomaticDecompression = System.Net.DecompressionMethods.GZip
});
var objTask = Client.GetStringAsync(objUrl);
objTask.Wait();
strResponse = objTask.Result;
strResponse = Client.GetStringAsync(objUrl).Result;
Why am I receiving a timeout via HttpClient?
Note:
Our WebApi is calling our WCF Service, which in turn is calling the 3rd party RESTful service via HttpClient---for security reasons I can't call the 3rd party API directly from our WebApi controller. The website is based on the .NET 4.0 Framework.
With lots of help from #jdweng and #gunr2171, I've realised the issue was due to the proxy stored in the App.Config on the self-hosted WCF Services. If I commented this out, I wouldn't get a time-out issue.
The HttpClient constructor can take in a HttpClientHandler, which has a Proxy property where you can bypass the local proxy as so:
return new HttpClient(new HttpClientHandler()
{
AutomaticDecompression = System.Net.DecompressionMethods.GZip,
Proxy = new WebProxy()
{
BypassProxyOnLocal = true
}
})
{
BaseAddress = new Uri("https:\\my.service")
};
I am using WebClient to get data from a web resource thus:
var wc = new System.Net.WebClient();
var stream = wc.OpenRead("http://...");
// etc..
It used to work until recently, when the server would forcibly close the connection.
Based on this StackOverflow answer, I added the ServicePointManager setting thus:
var wc = new System.Net.WebClient();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var stream = wc.OpenRead("http://...");
// etc..
… and it once again works as it did before.
I get that TLS is relevant to HTTPS and the effect of the setting is to include TLS1.2 in the handshake, and that the host site must have been recently updated to reject the older vulnerable protocol, but why is it necessary for ordinary, non-secure HTTP?
AllowAutoRedirect is set to true by default in WebClient instances.
Therefore, the request automatically follows redirection responses from your server.
Simply set AllowAutoRedirect to false and you will not follow any redirection, so you will not have to deal with SSL/TLS handshakes.
Of course, if your server does not want to serve your request with HTTP, you will not get the content you are looking for. Anyway, setting AllowAutoRedirect to false will help you confirm that the behaviour you encounter is due to a redirect.
I have two applications.
Both on the same server
Both running as the same service account
Both require windows Auth
I'm trying to use HttpClient to get from one app to the other with a simple post request; however, the identity doesn't seem to get used.
What I'm using looks like this:
var testIdentity = System.Security.Principal.WindowsIdentity.GetCurrent();
var handler = new HttpClientHandler()
{
UseDefaultCredentials = true
};
using (var client = new HttpClient(handler))
{
//...
HttpResponseMessage respose = client.PostAsJsonAsync("api/controller/Method", request);
response.EnsureSuccessStatusCode(); // Exception here!
//...
}
I've verified testIdentity is the service account I want to be running as, but it doesn't seem to make it. I always get a 401 response back.
I've also tested the application sending the request locally (but same domain), and the WebAPI on the server, but that doesn't work either (same 401 response).
If I have both applications local then it works as expected.
Any idea what I may be missing?
Little hesitant to accept this as the answer as I don't know the underlying cause yet; however, the issue I ran into was fixed by impersonating an account on a different domain.