Authenticating HttpClient calls from .NET Core on MacOS - c#

My question today is:
How to configure HttpClient so that it can authenticate the call without bothering the user on MacOS?
(.NET Core 2.2 console app running as Launch Agent on MacOS, calling a Web API on IIS with NTLM and Kerberos enabled, over our company's internal network)
Long story:
I have a .NET Core app that uses the following method to call a web api:
var handler = new HttpClientHandler()
{
UseDefaultCredentials = true
};
var client = new HttpClient(handler)
{
BaseAddress = new Uri("https://MyWebAPI.MyCompanyName.com/")
};
string result = client.GetAsync("MyEndpointSubURL")
.Result.Content.ReadAsStringAsync().Result;
When I run this on my Windows machine, the app easily connects and gets the result.
However, when I run this on a Mac, I get an exception:
Interop+NetSecurityNative+GssApiException - GSSAPI operation failed with error
The provided name was not a mechanism name. (unknown mech-code 0 for mech unknown).
at Microsoft.Win32.SafeHandles.SafeGssNameHandle.CreatePrincipal(String name)
Any ideas what I need to change to make it work?
We desperately want to avoid bothering the user with prompts (it's meant to be a background syncing service).
Recall, it's a .NET Core 2.2 console app running as Launch Agent on MacOS. The Web API it's calling is an Asp.NET Web API hosted with IIS with NTLM and Kerberos enabled and I only need to get past IIS (web API does not use any authentication/authorization mechanisms by itself). The API is exposed only over our company's internal network, so the user is already logged in to the network.

Try running kinit <username>#<DOMAIN> from the terminal and then running your program again. You may need to configure your krb5.conf file to properly point to the domain controller.
We have "default credentials" working in our system on Mac w/ .NET Core 2.1+ using the same code you show there. Configuring Kerberos through kinit and the conf file is the biggest challenge.
Based on what I can tell, .NET doesn't use the cache produced from running kinit, but this is what configures the principal to be used. .NET's interaction with Kerberos is poorly documented. See https://github.com/dotnet/corefx/issues/30203#issuecomment-395592407

I had a very hard time getting this to work on macOS with .NET Core 2.2.
I followed the online documentation about setting up your krb5.conf, running kinit and klist to make sure I had a valid kerberos ticket.
After all that, kerberos was working with Azure Data Studio, so I knew my setup was okay, but I could not get HttpClient with UseDefaultCredentials = true working. It always failed with the same error:
System.ComponentModel.Win32Exception: GSSAPI operation failed with error - An unsupported mechanism was requested (unknown mech-code 0 for mech unknown).
It did however work on a coworker's machine.
After a lot of digging, we discovered my coworker had .NET Core 2.2.7 installed while I only had 2.2.1. Upgrading my workstation to .NET Core 2.2.8 resolved my issue. Also rolling back our app to use 2.1.13 worked as well.
I hope this helps someone else in the future.

Try this:
With basic auth example.
var url = "https://MyWebAPI.MyCompanyName.com/";
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "Base64Credetials");
using (var response = await httpClient.GetAsync(url))
if (response.IsSuccessStatusCode)
{
var strResponse = await response.Content.ReadAsStringAsync();
MyObject result = JsonConvert.DeserializeObject<MyObject>(strResponse);
if (result != null)
{
//Your code here
}
}
}

I don't think MacOS has a concept of "default authentication" in the same way Windows does. Kerberos and NTLM are both Windows concepts. I suspect on MacOS you will have to use a different authentication scheme (Basic or Bearer) and then retrieve the credentials from somewhere such as the Keychain. IIRC an app can be granted silent read access to the key chain.

Related

Token access blocked when posting request from published Azure function

I am struggling to get a token from "https://login.microsoftonline.com/common/oauth2/token" with an Azure function by a post-request. The token will give permissions to access SharePoint though CSOM. Here is my code snippet with the post request:
var clientId = defaultAADAppId;
var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={HttpUtility.UrlEncode(username)}&password={HttpUtility.UrlEncode(password)}";
using (var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"))
{
var result = await httpClient.PostAsync(tokenEndpoint, stringContent);
var tokenResult = JsonSerializer.Deserialize<JsonElement>(result);
var token = tokenResult.GetProperty("access_token").GetString();
}
When testing locally, both when running the function in Visual studio and when I try with Postman, I am able to achieve an access token. However, as soon as I publish the function to my Function app in Azure I receive the following error message:
"AADSTS53003: Access has been blocked by Conditional Access policies. The access policy does not allow token issuance"
I have enabled an app registration in the portal and as mentioned, it all works fine until I publish everything to Azure.
Any ideas on how to solve this?
I got it to work now. First of all I reviewed the CA policies as #CaseyCrookston suggested. What I found out was that our CA policies blocked calls outside the country we operate from. However, the calls from the App registration/Azure function were registered from the Azure data centre location and thus, blocked by our CA policies. When running them locally the calls where registered in my country and therefore no errors were showing while debugging.
My first step was trying to add my Client app to the CA policy, which was not possible. The client/secret authentication that I used based on the suggestions in this CSOM guide by Microsoft prevented the App registration to be whitelisted from the CA policies (Github issue).
Based on this I had to change the authentication to a Certificate-based authentication as suggested here: Access token request with a certificate and here: SO answer. With this I was able to whitelist the App registration in the CA policies and successfully authenticate to the Sharepoint CSOM.
As the error message says, your app is blocked by CA policy. Possible causes can be unknown client app, blocking external IP addresses, etc.
You can perform one of the below workarounds:
Add your Client app to your CA policy.
I wouldn’t recommend this because this affects your security - if you take the risk you could exclude the “Microsoft Azure Management” from your CA policy which blocks unknown clients / requires device state and still protect the sign-in with MFA.
A better approach is to use another OAuth 2.0 and OpenID connect flow like the delegated flow where you sign-in directly within the app, if possible.

C# publish Web Core App to Azure problems with external login (Google Api)

i developed an application with the DotNet Core Web Technology on my computer with an external login with Google. Locally the application works. After publishing the application to the azure, I noticed, that I can not login on azure with my google account. I debugged the app and noticed, that the ExternalLoginAsync function returns null. Therefore I can not login with my external account. Afterwards i looked at the network stream and detected that the signin-google page is requested from google with the parameter "&prompt=none". If i look at the network stream on my local computer, I see that the paramter is "&prompt=consent".
My Configurations looks like that:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddGoogle(google =>
{
google.AccessType = "offline";
google.SaveTokens = true;
google.ClientId = "xxxyy";
google.ClientSecret = "xxyyyytt";
});
Does anyone know, why the external login is not working?
Best regards

Authorization has been denied for this request - Desktop to ASP.NET Web API

I have been banging my head against a wall for some time now.
Desktop WPF app calling a ASP.NET Web API.
I am using the [AUTHORIZE] annotation on the ASP.NET app. This is where the problems have started.
Using MSAL from the WPF app.
static App()
{
_clientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(AzureCloudInstance.AzurePublic, Tenant)
.WithDefaultRedirectUri()
.Build();
}
ClientId refers to the app registration of the desktop app in Azure.
string[] scopes = new string[] { "api://****-f56f-4cec-a771-dbdb5d43f047/access_as_user" };
var accounts = await App.PublicClientApp.GetAccountsAsync();
AuthenticationResult authResult;
try
{
authResult = await App.PublicClientApp
.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
catch (Exception)
{
authResult = await App.PublicClientApp
.AcquireTokenInteractive(scopes)
.ExecuteAsync();
}
App registration for the web api is also there. I have set up the scope via 'Expose an API' and given delegated permission to the desktop app to call into the web api.
When I call in I get
StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers
I can call a non AUTHORIZE endpoint no problem, so the api is working fine.
I have endlessly been through the MSAL documentation.
Things I am unsure about.
AppRoles in the manifest.
Do they need to be authorised anywhere apart from adding to the manifest?
Do I leave App Service (Web api) as 'Anonymous access is enabled on the App Service app. Users will not be prompted for login.' Is MSAL taking care of that.
I am assuming you can either use MSAL code or secure the api via AD (Authenication/Authorization)
I have dug myself in a hole and can see out right now, so excuse me a little.
Thanks
please take a look at: https://learn.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad#-configure-with-advanced-settings
at the top of that document there is a note saying:
Note
The express settings flow sets up an AAD V1 application registration. If you wish to use Azure Active Directory v2.0 (including MSAL), please follow the advanced configuration instructions.
basically means that you can't really use msal with the express setup. but can with advanced.
then the section under it describes what you need to do for a desktop app in terms of adding api permissions to your app service.
Hopefully this puts you a bit on the right track, if not please comment further and i will try to help as much as possible.

SSO with AD/ADFS and .NET Native Client

My Question is about Active Directory (AD), Active Directory Federation Services (ADFS), Single Sing On (SSO) and SAML.
We have a Client/Server Application with the following Specs:
- Client: WPF .NET Native Client based on .NET 4.7.2 and C#
- Server: REST-Service based on Java Spring
One main Requirement is SSO with AD/ADFS.
In Best Case the User should be authenticated seamlessy/silent.
The main Restriction is AD and ADFS based on Windows Server 2012 R2.
In the following Picture you can how we planned to implement SSO with ADFS.
SSO-Scenario
The .NET Native Client tries to use the REST-Service without Authentication.
The REST-Service redirects the .NET Native Client to ADFS-Server.
The .NET Native Client tries to get a SAML-Token with the current logged on User-Credentials(Windows Logon).
If the current User ist granted the ADFS-Server respond with and SAML-Token.
The .NET Native Client takes the SAML-Token and passes it to the REST-Service.
If the SAML-Token is accepted the User Access is granted.
If the SAML-Token is not accepted the User should get an Login-Screen in the App.
At this time im totally confused about SSO with ADFS in .NET Native Client.
I can't find any suitable Demos etc.
Many Demos or Use Cases are about ASP.NET but almost nothing about Native Clients.
I'm starting to wonder if my assumption about SSO with AD/ADFS and SAML aren't true.
I started building an AD-ADFS-Lab with Virtual Machines described in Understanding ADFS an Introduction to ADFS.
Then I'm trying to play with the ADFS-Server but couldn't get it done.
I was looking at this Libraries:
ADAL.NET
MSAL
After 1 week of Research my Head is spinning:
Do I need WIF?
What about WCF?
I know there is OAuth. I know Windows Server 2012 isn't the lastest and best for this Scenario. But the Requirements and Restrictions come direct from our Customer.
What can I do?
What can I read or try?
Are thre any other Libraries?
Are there any Examplex?
Update
I was able to "talk" to my ADFS-Server with WS-Trust and get a SAML-Token.
private static void Main(string[] args)
{
string adfs = "https://ad-fs.adlab.local";
string adfsEndpoint = "https://ad-fs.adlab.local/adfs/services/trust/13/usernamemixed";
string appServer = "https://ad-server.adlab.local/sampapp/";
var factory = new WSTrustChannelFactory(new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential), adfsEndpoint);
factory.TrustVersion = TrustVersion.WSTrust13;
var channelCredentials = factory.Credentials;
channelCredentials.UserName.UserName = "Administrator#adlab";
channelCredentials.UserName.Password = "SsoLab2019";
channelCredentials.SupportInteractive = false;
RequestSecurityToken rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointReference(appServer),
KeyType = KeyTypes.Bearer
};
var channel = factory.CreateChannel();
try
{
var token = (GenericXmlSecurityToken)channel.Issue(rst);
Console.Write(token.TokenXml.OuterXml);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
No I have to figure out how I can get the SAML-Token silent/seamless.

Office 365 "535 5.7.3 Authentication unsuccessful"

I created an WebApi in Asp.Net Core 1.1, which is hosted in Azure. Sending e-mails is a part of this Api. To do this, I used MailKit.SmtpClient with following code:
using (var client = new SmtpClient())
{
client.LocalDomain = "smtp.office365.com";
await client.ConnectAsync("smtp.office365.com", 587, SecureSocketOptions.StartTls).ConfigureAwait(false);
client.AuthenticationMechanisms.Remove("XOAUTH2");
client.Authenticate(Constants.AccountData.Login, Constants.AccountData.Password);
await client.SendAsync(mimeMessage).ConfigureAwait(false);
await client.DisconnectAsync(true).ConfigureAwait(false);
}
It works very well until last week. Since then, each time I make
client.Authenticate(Constants.AccountData.Login, Constants.AccountData.Password);
I become error 535 5.7.3 Authentication unsuccessful
I checked the O365 Account and I could normally log in to O365 using Microsoft Login Page and the credentials we use in the App. To be sure, we have changed the password for this account, but this did not help.
I decided to migrate the App to .Net Core 2.0 and check with SmtpClient from .NET libraries. I published the migrated App to Azure and cofigured the SmtpClient as in this post -> https://blogs.msdn.microsoft.com/benjaminperkins/2017/01/11/sending-email-from-an-azure-web-app-using-an-o365-smtp-server/
Right now I become Timeout (The operation has timed out.).
When the property EnableSsl = false, then I become some other Error, that the connection is not secured.
I tried also set the property
client.TargetName = "STARTTLS/smtp.office365.com";
but it does not help.
Does anyone have an idea what can i do to make it work?
I have the feeling that the problem is somewhere else (maybe in o365), but i do not know where to look... Any suggestion will be very helpful.

Categories