Send request to WebAPI as service account - c#

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.

Related

Calling Azure Function app works in console but not in xamarin forms

So I created a function which is a Get request. All the function does is retrieves some data from an SQL database and returns it.
I call this function in a console app, just to test it, and all is working as it should.
I then copy the code and paste it into my xamarin.forms app for android.
When I run it it immediately gives me a 404 Not found response.
Any idea why it's not working in the xamarin app but is working in the console app?
using (var client = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Get, "http://{MySite}.azurewebsites.net/api/{myfunction}/"))
using (var httpContent = CreateHttpContent(new DiaryDate() { Date = DateTime.Today }))
{
request.Content = httpContent;
using (var response = await client
.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
.ConfigureAwait(false))
{
if (response.IsSuccessStatusCode)
{
// do something
}
}
}
CreateHttpContent just converts the given object to JSON.
Update the URL to https scheme (https://{MySite}.azurewebsites.net/api/{myfunction}/). Firstly, there is no reason for choosing non-secure channel. Azure Function side won't require any change to use https. Secondly, as pointed out in the other answer, there is restriction in client side for http which would require tweak to unblock.
UPDATE: In this particular call, you are using Http GET, but sending a request content (json of DiaryDate object). So, it will send that via query string in the the URL. Though I am not yet sure how it's working in console app (might be something to do with how it's handled in Xamarin/Mono http handler v/s that of .net core in console app in GET request), but it should be POST surely. Can you change HttpMethod.Get to HttpMethod.Post in the line where you are creating HttpRequestMessage.

Using GET request causes bot dialog to fail

I've connected my bot application to the direct line API which is published with Azure. I am currently testing the application with a command line client application, the bot framework emulator, and the dev.botframework.com homepage for my bot.
Everything works correctly until I attempt to submit a GET request to a REST API. I've tested the GET API request in a separate project and it works correctly and the GET request worked prior to implementing the direct line channel. Is there anything I need to be aware of when making http requests with the direct line on the bot side?
Code in question
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", headerParam);
var response = client.GetAsync(new Uri("someUrl.com/api/v1/auth")).Result;
string content = response.Content.ReadAsStringAsync().Result;
var jo = JObject.Parse(content);
this.token = jo["Result"]["Token"].ToString();
}
await context.PostAsync(this.token);
the line that actually causes the failure is
var response = client.GetAsync(new Uri("someUrl.com/api/v1/auth")).Result;
Also is there an easier way to debug a project when it's published to azure and running direct line API?
System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions ipaddress
I have tried to invoke my custom REST API within my bot application back-end, then I could leverage Remote debugging web apps to retrieve the result from my bot application hosted on Azure web app as follows:
After searching for the related issue, I found that there be limitation for the number of sockets of your current app service plan when creating the new outgoing connections. You could try to scale up your App Service plan or create a new web app to isolate this issue. For more details, you could refer to this similar issue and this blog.

Check url with NTLM on server side

I need to check if url exists and can be reached. In order to do it I send Get request and handle the status:
var httpClient = new HttpClient();
var response = httpClient.GetAsync(new Uri(pageUrl));
isPageAccessible = response.Result.StatusCode == HttpStatusCode.OK;
However, the server uses NTLM for authentication. As I found it here, there are several steps (requests) before I get success OK status. For the first request I get 401 Unauthorized status and can't go to further steps.
All in all, how can I check url on the server with NTML upon completion of all requests?
If you are accessing an authenticated server, you should provide credentials. Credentials of running process for NTLM can be provided with HttpClient as below:
var handler = new HttpClientHandler {
Credentials = System.Net.CredentialCache.DefaultCredentials
};
var httpClient = new HttpClient(handler);
var response = httpClient.GetAsync(new Uri(pageUrl));
You're setting yourself up for failure since there are dozens of reasons why a request may not return a 200 OK response. One may be that the response has no content 204 No Content. Another may be that the request only accepts POST or PUT requests. Another, as you've discovered, may be that it has an authentication system in front of it 401 Not Authorized. Another may be just that the response is a redirect 301 Moved Permanently or 302 Found. Or it could be behind a proxy 305, 306, etc.
The only way you can determine if a URL really exists is to request that the other end prove it. Google does it, Facebook does it, Pinterest does it, etc. The way they do it is they ask the sender to set an MX record in their DNS or a meta tag on their index.html with a custom token they generate. If the token exists, then they're who they say they are.
Anything else is unreliable.

HttpClient strange behavior when trying to access WCF Rest service with Windows Auth

I am creating a client-server application using WCF REST services (.Net 4.0) and I see really strange error there. To access the service I use HttpClient class, the code looks like:
public TResponse Post<TRequest, TResponse>(Uri uri, TRequest request)
using (HttpClient client = new HttpClient())
{
client.TransportSettings.Credentials = CredentialCache.DefaultCredentials;
client.TransportSettings.ConnectionTimeout = TimeSpan.FromSeconds(200);
using (HttpResponseMessage response = client.Post(uri, HttpContentExtensions.CreateDataContract(request, null)))
{
response.EnsureStatusIsSuccessful();
return response.Content.ReadAsDataContract<TResponse>();
}
}
}
I host my service on IIS7 and when anonymous auth is enabled everything works well, but when I turn on windows auth some random requests (in average 1 of 10) get failed with 400-Bad request status and error message is : Bad Request - Invalid Verb. HTTP Error 400. The request verb is invalid.
What could it be?
And a little update: if fiddler is turned on everything works perfect.
I just ran into the same thing here. Quite a mystery really. I don't understand why having fiddler running removes the problem.
I eventually found that the issue was caused the by the "expect continue" header being added to the post. I removed that and the post succeeds instead of the 400 bad request.
Here's a good entry about it: http://blogs.msdn.com/b/jaskis/archive/2009/04/19/asmx-post-request-fails-with-http-400-error-when-content-length-size-increases.aspx
In my case this was apache HTTP Client v4.0 so,
httpClient.getParams().setBooleanParameter(
CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
did the trick.

Should WebRequest.CachePolicy work from code running within IIS?

I have some code running within an ApiController (ASP.Net Web API) that itself wants to make a GET request to another web service. The web service (also part of my app) returns Cache-Control headers indicating an expiry time for the content it returns.
I am using the new System.Net.Http.HttpClient, configured with a WebRequestHandler in order to use client-side caching (the default HttpClientHandler does not support cache configuration, although it does use System.Net.WebRequest as its underlying HTTP implementation):
var client = new HttpClient(new WebRequestHandler {
UseDefaultCredentials = true,
CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default)
});
var response = client.GetAsync("someUri").Result;
response.EnsureSuccessStatusCode();
On the server I am enabling caching within my controller action via...
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.CacheControl = new CacheControlHeaderValue {
Public = true,
MaxAge = new TimeSpan(0, 5, 0); // Five minutes in this case
};
// Omitted, some content is added to the response
return response;
The above (abbreviated) code works correctly within a test; I make multiple calls to the service in this way and only the first call actually contacts the service (observed via log messages on the service in IIS); subsequent calls use the cache.
However, running the same code hosted on IIS itself, it seems the HttpClient ignores the caching result (I have also set up my IoC container such that only one instance of the HttpClient exists in the AppDomain) and calls the service each time. This is running as the AppPoolIdentity.
Interestingly, if I change the app pool to run as NetworkService, then the response has status code 401 Unauthorized (I have tried setting Preauthenticate = true on the WebRequestHandler but the status code is still 401). The same is true if I change the app pool to run under my own credentials.
So, is there something about running the App Pool under the NetworkService identity, and virtual AppPoolIdentity, that prevents them from using client-side caching. Where does the content cached by WebRequest physically exist anyway?
WinInet caching is not supported when running on IIS, please check the following support article from MS http://support.microsoft.com/kb/238425
I don't see any reason why the cache should not work under IIS. The cache is implemented by WinINetProxy and is the same cache that is used by Internet Explorer.
Try setting the max-age instead of the expiry time.

Categories