How to make HttpClient to use the app pool identity - c#

I'm trying to make an http call from website A to website B, using the website A's identity.
Using .Net fwk 4.x, I just have to make something like that:
using (var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }) {
// Do something
}
In aspnetcore 2.2, an IHttpClientBuilder has been provided to manage http clients.
The same code is supposed to look to something like this:
services.AddHttpClient("myOtherSite", httpClient => {
httpClient.BaseAddress = new Uri("http://something");
})
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler {
UseDefaultCredentials = true
});
Then I just need to inject the IHttpBuilder where I need a client then call clientBuilder.buildClient("myOtherSite").
Using this, http request seems to be made without the pool user, despite the documentation..
Has someone done something like this?

I'm not sure if this is your issue but this Microsoft Documentation states that starting with core 2.1, the System.Net.Http.SocketsHttpHandler class is used instead.
It has information on how to configure to allow continuing use of HttpClientHandler but you may want to switch or even try using HttpMessageHandler in place of the type you're using for the handler currently.

Related

Using Blazor Client-Side consuming Web API with Windows Authentication

Currently I've got an application running with and angular client, consuming a Web API with Windows Authentication.
Now I'm looking into replacing this front end with Blazor (client-side), however I'm facing some challenges when it comes to authentication.
In angular I just set withCredentials to true in order to submit the required information.
The code below works as intended using Blazor server-side, but since I want to use Blazor client-side it's not an option and doesn't help me much.
IEnumerable<SearchView> searchResults;
int NumberOfItems;
protected override async Task OnInitAsync()
{
using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
{
var result = await client.GetJsonAsync<Response<SearchView>>("http://localhost:80/search");
NumberOfItems = result.TotalItemCount;
searchResults = result.Items;
}
}
}
The above code throws an "PlatformNotsupportedException".
WASM: System.PlatformNotSupportedException: System.Net.Http.HttpClientHandler is not supported on the current platform.
WASM: at System.Net.Http.HttpClientHandler.set_UseDefaultCredentials (System.Boolean value) <0x1d63160 + 0x0000c> in <4399d2484a2a46159ade8054ed94c78e>:0
Clearly the code provided is not supported using Blazor client-side, but if there are any alternative ways to achieve what I want to, any pointers and help would be appreciated.
I've just hit the same problem and couldn't get it working with HttpClient, but I did manage it with a HttpRequestMessage:
string APIURL = "https://localhost:44390/api/models";
// create request object and pass windows authentication credentials
var request = new HttpRequestMessage(HttpMethod.Get, APIURL);
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
// send the request and convert the results to a list
var httpResponse = await Http.SendAsync(request);
models = await httpResponse.Content.ReadFromJsonAsync<myModel[]>();
This is not (yet) possible. Blazor client-side runs on the Mono runtime of the .net framework which does not support Windows Authentication.
Your best option is to implement a token based auth (JWT for instance) and use ADFS.

Request.HttpContext.Connection.ClientCertificate is always null

I have an ASP.Net core website deployed on Azure app service for Linux.
In the controller, I am trying to get the client certificate like below:
var callerCertificate = Request.HttpContext.Connection.ClientCertificate;
I always get callerCertificate as null.
I have tried await Request.HttpContext.Connection.GetClientCertificateAsync() with same result null.
My website webhost creation looks like below:
WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseStartup<Startup>()
.UseSerilog();
I have also set SSL setting for the website (in Azure) as below:
The client side caller is a net462 project that uses Microsoft.Rest.CertificateCredentials to set the certificate to HTTP request.
var cred = new CertificateCredentials(_deviceCertificate)
...
await this.cred.ProcessHttpRequestAsync(_httpRequest, cancellationToken).ConfigureAwait(false);
You could try to add the certificate using HttpClient directly instead of using Microsoft.Rest.CertificateCredential.
var clientHandler = new HttpClientHandler();
clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
clientHandler.ClientCertificates.Add(_deviceCertificate);
var client = new HttpClient(clientHandler);
var result = client.GetAsync("https://yourservice").GetAwaiter().GetResult();
You may also need to configure the SSL protocol (SSL2, SSL3, TLS, etc.):
clientHandler.SslProtocols = SslProtocols.Tls;
Answering my own question:
I am able to get the client certificate from header
string clientCertFromHeader = Request.Headers["X-ARR-ClientCert"];
Though, it is still a mystery as to why Request.HttpContext.Connection.ClientCertificate is not giving the certificate.

Using Default Credentials in System.Net.HttpClient request in UWP

We are porting our Windows 8.1 app to UWP and are experiencing an issue with sending default user credentials for single sign-on. It seems that credentials are not being set, despite setting UseDefaultCredentials = true on the handler. This exact code was working in Windows 8.1.
using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
{
// client._handle.Credentials is null
// This call fails authentication with a 401
// and Fiddler shows no attempt to pass authentication
var response = await client.GetStringAsync(new Uri(GlobalConfig.Config.BaseUri, "Presenter/SingleSignOn"));
...
}
As noted above, in debugging I can see that client._handle.Credentials is null.
I have also tried setting credentials from the System.Net.CredentialCache, but these appear to return empty credentials and they also result in a null client._handle.Credentials.
var handler = new HttpClientHandler() { Credentials = System.Net.CredentialCache.DefaultCredentials };
var handler = new HttpClientHandler() { Credentials = System.Net.CredentialCache.DefaultNetworkCredentials };
I have double-checked our declared Capabilities as per this answer and they look fine. We have declared capabilities:
Enterprise Authentication
Internet (client)
Private Networks (Client & Server)
Removable Storage
I have tried using Windows.Web.HttpClient, but it has the same issue--it doesn't find default credentials, so it prompts via a UI. Am I missing something obvious? Or something non-obvious?
TL;DR - I am having trouble passing default user credentials in HttpClient requests.
Edit: I should add that authentication in general is working. If I pass a username/password explicitly, then it works. Obviously, that's not the goal here.

How to fire off SignalR hub from external application (that doesn't use SignalR)

I have an Asp.Net MVC 4 application (Application A) that will use SignalR for real time updates to users. I am using SignalR version 1.1.4 due to older .net framework version we are working with.
There is an external application (Application B) that when an order is submitted, I want to notify application A to send a notification of order.
My initial thoughts are to either create an ASP.NET Web Service to host SignalR, but because application B will not use SignalR I figure that just making a call to the controller of application A passing necessary data will work for what is needed.
So, from application B, how would I call application A's controller to pass the data necessary? Can Ajax be used to make a call to an external app? If so, what would the controller method look like?
These are both intranet applications with windows authentication.
I figure that just making a call to the controller of application A
passing necessary data will work for what is needed
You can use the HttpClient in Application B to call a Controller Action in Application A.
Example of creating an Order and sending the order to another MVC application controller (not tested).
private HttpClient client = new HttpClient();
public HomeController()
{
client.BaseAddress = new Uri("http://localhost:49277");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
[HttpPost]
public ActionResult Insert(Order order)
{
HttpResponseMessage response = client.PostAsJsonAsync<Order>("/Order/Post" + $"/{order.OrderID}", order).Result;
return RedirectToAction("Index");
}
EDIT
You can use - UseDefaultCrendentials or pass the credentials directly.
using (var handler = new HttpClientHandler {UseDefaultCredentials = true})
{
using (var client = new HttpClient(handler))
{
...
}
}
OR
var credentials = new NetworkCredential(userName, password);
using (var handler = new HttpClientHandler {Credentials = credentials })
{
using (var client = new HttpClient(handler))
{
...
}
}

Is there a way to generate an access token from within Identity Server without using the endpoints?

I'm building an identity server deployment (Identity Server 4, hosted in an ASP.NET Core MVC application). As a part of the new user registration process, I need the identity server application to make a request against another API. I'd like to use, basically, the client credential flow to make this request, but instead of having the identity server make an http request against its own endpoint, would it be possible to just programmatically generate the token in C#?
What I'd like to do would be something like this:
public class AccountController : Controller
{
[HttpPost("register")]
public async Task<IActionResult> Register(UserRegistrationModel model)
{
// do stuff like validate model, create user, update database, etc
// generate access token for other API
var client = identityServer4DbContext.Clients.FirstOrDefault(c => c.Id = "myself");
var token = tokenService.CreateAccessToken(client, StandardScopes.All.Concat(scopeForMyOtherApi));
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://myotherapi/");
var result = await httpClient.GetAsync("resource/info-i-need");
// do something with result.
}
}
I saw that there is an ITokenService in IdentityServer4, but it requires a TokenCreationRequest populated with stuff you only get when you have an http request (for a token) to handle, so it seems that it is only useful to IdentityServer4 itself.
I also recognize that I could use the IdentityModel client to make a request against my own endpoint, but that would involve a bit more configuration that I'd like to avoid - not to mention that it seems like I shouldn't have to do that from within the identity server application itself.
In IdentityServer 3 it was possible to call IssueClientToken() OWIN extension method.
In IdSrv 4, use IdentityServerTools.IssueJwtAsync() and IssueClientJwtAsync().

Categories