C# HttpClient failing to make GET requests with Windows Authentication - asp.net-core

I have a .NET Core 3.1 Api application with the following configuration of HttpClient. In Startup.cs
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddHttpClient("myapi", c =>
{
c.BaseAddress = new Uri(Configuration["endpoint"]);
c.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
IISDefaults.AuthenticationScheme, Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes($"{Configuration["username"]}:{Configuration["password"]}")));
});
I then try to make an HTTP call like this:
var client = clientFactory.CreateClient(clientName);
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStringAsync();
however I always get an Unauthorized response when calling an internal api. Under Debug I have Windows authentication and Anonymous authentication both enabled.
With Postman my api calls go through, which verifies that I got the right credentials.
Can you suggest any alterations to make this work?

Instead of c.DefaultRequestHeaders.Authorization =, I'm having config like this
c.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
Credentials = new NetworkCredential("username", "password"),
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
PreAuthenticate = true
});
I guess this will not work as-is in your case, but I hope this can get you on track.

Related

Api calling in .net core razor pages

I am working on (built-in web apis) provided by whatsapp business api. As a newbie in .net core razor pages and web apis. I want to know how can I get access to the body of the post request api. Take an example below for sending a message
Post: {URL}/v1/messages
Request Body:
"to": "",
"message_type:"
"message_text:"
"recipient_type: "individual | group""
How can I make a call to the builtin api and access the body parts of it?
Ofcourse, we as a developer can use postman for checking the working of api. But take this as a client and for the client we have some fields like
To:
Message:
How can take these fields and put it into the api call body and then when the user click on the send, the api call works and shows whatever we want to show the user for example a model with send successfully etc.
You can call the API using HttpClient.
Add the URL in await client.PostAsync() function. If you have authorization use client.DefaultRequestHeaders.Authorization otherwise omit it
string myContent = "";
string myJson = <JsonQuery>;
using (HttpClient client = new HttpClient())
{
// If any authorization available
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenLabel.Text.Trim());
using (HttpResponseMessage response = await client.PostAsync("https:url", new StringContent(myJson, Encoding.UTF8, "application/json")))
{
using (HttpContent content = response.Content)
{
myContent = await content.ReadAsStringAsync();
}
}
}
Update
Content
string myJson = "{\"subject\": }";
URL
using (HttpResponseMessage response = await client.PostAsync("{{URL}}/v1/groups", new StringContent(myJson, Encoding.UTF8, "application/json")))
Header
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "");

NTLM Auth with RestSharp

I am attempting to create some tests using RestSharp for a project I am working on.
This project uses Single Sign-on NTLM Authentication.
I am attemping to use a NTLMAuthenticator but my getUser request is always failing. I am not positive what URL to put in for the CredentialCache, the project or the SSO Id Provider.
SharedRequests shared = new SharedRequests();
var credential = new CredentialCache
{
{
new Uri("project or ID Provider URL or something else?"),
"NTLM",
new NetworkCredential("doamin\Username", "Password")
}
};
RestClient client = new RestClient();
client.BaseUrl=new Uri("projectURL");
client.Authenticator = new NtlmAuthenticator(credential);
client.PreAuthenticate = true;
RestRequest request = shared.GetCurrentUser();
IRestResponse response = client.Execute(request);
my response always gets a 500 error which is what is expected when no auth cookies are present.

.NET Core 2 programmatically authentcation on Keycloak example

I'm trying to authenticate through a device (it's a barcode reader) that use .NET Core. I'm a newbie on .NET Core.
Now I need to write some program that gives me the possibility that given a username/password I make authentication on a Keycloak server with openidconnect. Is there some sample that shows how from a username/password string I can make the authentication programmatically?
I find a lot of examples that use .NET Core as a server that has Controllers that exposes rest API for user that have to be authenticated. But I need some example/hint to follow where the .NET Core makes the request.
Update
I could figure out (with curl) what exactly I have to do. Two calls to the Keycloak server.
call:
http://keycloakserver/auth/realms/realmName/protocol/openid-connect/token?grant_type=password&client_id=demo-app&username=username&password=password
This gives me back an object containing the access_token.
invoke the secured service adding in the header
"Authorization: bearer +access_token"
I try to develop this two calls with .NET Core.
I found this way to resolve it. But I'm sure is not the best way. I think there is a lot of improvement of security:
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");
var values = new Dictionary<string, string>
{
{ "client_id", "myClientId" },
{ "grant_type", "password" },
{ "username", "usernaName" },
{ "password", "password" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://domain/auth/realms/realmName/protocol/openid-connect/token", content);
var responseString = await response.Content.ReadAsStringAsync();
var responseToken = JsonConvert.DeserializeObject<ResponseToken>(responseString);
Console.WriteLine("accessToken: " + responseToken.AccessToken);
var client2 = new HttpClient();
client2.DefaultRequestHeaders.Accept.Clear();
client2.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
client2.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");
client2.DefaultRequestHeaders.Add("Authorization", "bearer "+ responseToken.AccessToken);
var dataResponse = client2.GetStreamAsync("http://serviceDomain/api/SampleData/WeatherForecasts");
var serializer = new DataContractJsonSerializer(typeof(List<Weather>));
var tempData = serializer.ReadObject(await dataResponse) as List<Weather>;
Console.WriteLine(tempData);
If you have a better solution then don't hesitate to post it.

Retrieving access token in controller

I am developing an ASP .Net Core 1.1 MVC web app which calls a web API using the "Authorization Code Grant Flow". I am using Auth0 for the authentication server.
Following the Auth0 tutorials, at the point the user has successfully logged in to the web app, and now does something that makes the web app call upon the web api, it says I should get the access token as follows:
public async Task<IActionResult> Index()
{
string accessToken = User.Claims.FirstOrDefault("access_token")?.Value;
if (accessToken == "")
return View("Error");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage responseMessage = await client.GetAsync(inspectionsUrl);
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
List<Inspection> inspections = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Inspection>>(responseData);
return View(inspections);
}
return View("Error");
}
However, this doesn't even compile, giving the following
Argument 2: cannot convert from 'string' to 'System.Func <System.Security.Claims.Claim, bool>'
Any ideas?
The first line should probably be:
string accessToken = User.Claims.FirstOrDefault(c => c.Type == "access_token")?.Value;
Right now you are trying to give "access_token" as an argument to FirstOrDefault, which won't work. You have to specify a predicate.
This is much easier, you don't even need to include your token to claims.
var token = await HttpContext.GetTokenAsync("access_token");
Documentation
You can write extension and use more elegant way for retrieving access token:
var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");

How to delegate Identity from Web-Application to WebAPI

I am trying to build a website, where the user logs in at the and can use an backend web-API.
Calls to the backend web-API will always be proxied by the frontend website, since the backend is not publicly available.
Back- and frontend are MVC 6 (or MVC Core?) projects based on ASP.net Core.
The frontend currently authenticates (successfully) by using OpenId-Connect.
The backend should use JwtBearerToken.
The authentication so far requests the response type is id_token code and the scope is openid profile.
After the roundtrip to the Auth-Server (ADFS 2016), I will end up in the AuthorizationCodeReceived-Event from ASP.NET, but I have no luck in exchanging the code for authorization token. I tried the following using ADAL:
public override async Task AuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
{
await base.AuthorizationCodeReceived(context);
var clientCredential = new ClientCredential(context.Options.ClientId, context.Options.ClientSecret);
var oAuthContext = new AuthenticationContext(context.Options.Authority, false);
var oAuthResult = await oAuthContext.AcquireTokenByAuthorizationCodeAsync(context.Code, new Uri(context.RedirectUri), clientCredential);
}
I had to disable the authority validation (which I do not like) and I do not get results other than Http-Status 400.
I'd be happy for any advice how to move on.
Update
Further Investigation Shows, that the OpenIdConnect-Configuration allows to save auth and refresh Tokens into the Claims. Nevertheless I don't see the possibility to convert it in the first place.
I also tried exchanging the code by hand (PS: Invoke-WebRequest ...) but had no success. Perhaps this is a problem of ADFS TP4...
I've managed to get this scenario to work with TP4.
AuthorizationCodeReceived = async n =>
{
string code = n.Code;
AuthenticationContext ac = new AuthenticationContext(BaseAddress, false);
ClientCredential client = new ClientCredential("clientid", "secret");
string resourceId = "https://myservices/myapi";
AuthenticationResult ar = await ac.AcquireTokenByAuthorizationCodeAsync(code, new Uri("https://localhost:44300/"), client, resourceId);
}
You can then use the access token from a controller method like this:
AuthenticationContext ac = new AuthenticationContext(Startup.BaseAddress, false);
ClientCredential cred = new ClientCredential("clientid", "secret");
string resourceId = "https://myservices/myapi";
AuthenticationResult ar = ac.AcquireTokenSilent(resourceId, cred, UserIdentifier.AnyUser);
var client = new HttpClient();
client.SetBearerToken(ar.AccessToken);
var result = await client.GetStringAsync("http://localhost:2727/identity");