Office 365 "535 5.7.3 Authentication unsuccessful" - c#

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.

Related

Unable to send email in C# Less secure app access not longer available

I have an winform application running on our production floor and it sends email for reporting, so since yesterday its unable to send emails and i got this message
"The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Authentication Required."
I checked this post
The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required?
and I found that google is not longer supporting 3rd party app, it doesn't allow less secure apps
this is from google less secure app
Less secure app access:
Some apps and devices use less secure sign-in technology, which makes your account vulnerable. You can turn off access for these apps, which we recommend, or turn it on if you want to use them despite the risks. Google will automatically turn this setting OFF if it’s not being used.
This setting is no longer available. Learn more
so I have tried adding SmtpServer.UseDefaultCredentials = false; but nothing works, I think the issue is google that is not longer supporting 3rd party access to email.
This is my code
try
{
MailMessage mail = new MailMessage();
System.Net.Mail.SmtpClient SmtpServer =
new System.Net.Mail.SmtpClient("smtp.gmail.com");
string sender = "user#gmail.com";
mail.From = new MailAddress(sender);
mail.To.Add("receiver#plastikon.com");
mail.Priority = MailPriority.High;
mail.Subject = subject;
mail.IsBodyHtml = true;
mail.Body = ($"{body} \n Name of computer: { HostName} ");
SmtpServer.Port = 587;
SmtpServer.Credentials = new
System.Net.NetworkCredential("user#gmail.com", "Password");
SmtpServer.EnableSsl = true;
SmtpServer.UseDefaultCredentials = false;
SmtpServer.Send(mail);
}
The question is: is there a solution for this or does anyone can recommend me another way to send emails or an API or something?
The deactivation of less secure applications prevents you from being able to log in directly with your username and password, but it does not prevent you from being able to generate a specific password for your application. Now, instead of logging in with your google password, you'll log in with a password that you generate for your specific app.
The solution is simple and does not require much change:
Turn on 2-Step Verification in your google account. This step is required as Google only allows generating passwords for apps on accounts that have 2-Step Verification enabled.
Go to generate apps password (https://myaccount.google.com/apppasswords) and generate a password for your app.
Simply use your gmail username (your_mail#gmail.com) and the password generated in your c# application.
I have tested that it works with a small console application that I am attaching below:
using System.Net;
using System.Net.Mail;
string username = "your_mail#gmail.com";
string password = "generated_password";
ICredentialsByHost credentials = new NetworkCredential(username, password);
SmtpClient smtpClient = new SmtpClient()
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
Credentials = credentials
};
MailMessage mail = new MailMessage();
mail.From = new MailAddress(username);
mail.To.Add(username);
mail.Subject = "Testing less secure apps new configuration.";
mail.Body = "Hello stackoveflow!";
smtpClient.Send(mail);
And it works perfectly:
If you get this error
The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Authentication Required
You may also want check your email and confirm you added app password.After confirming i was able to send email.
https://i.stack.imgur.com/iswPV.png
For starters, don't use SmtpClient. That class is obsolete and Microsoft itself advises against its use in the documentation. SmptClient simply doesn't support newer protocols, much less authentication protocols like OAuth. The proposed alternative is to use MailKit
MailKit can connect both in a less secure mode or by using OAuth. Connecting to GMail in general is described in the FAQ.
The doc page Using OAuth2 With GMail (IMAP, POP3 or SMTP) shows how to create a Google API project, configure it for GMail access and OAuth authentication and finally, shows how to send emails. The doc page shows how to handle authentication for both desktop and web applications
Dealt with this today. Just go to the gmail account, then go to Manage Your Google Account > Security.
From here enable 2-factor authentication, then once you have done You will see the "App passwords" option appear under the 2-step verification option. Click on this, name the device that you want to use, and then copy & paste the generated password that you are given into your code in place of the old password that you were using.
I've done this now for our office printer & the python script that I had to automatically deliver timesheets to everyone.

Mailkit Office365 AcquireTokenInteractive requires client_secret

So this is an issue that has been plaguing me for a bit and my deadline is coming up. I'm working on an application that sends emails and my workplace uses Office365 via Exchange. I'm using a C# webapp and using Mailkit to deliver emails.
The issue (not really an issue but good practice that's getting in my way) is that we made an email account to deliver mail yet our organization requires MFA. After talking about it with my director, creating an app password would not be a good idea for how this program is deployed so I'm trying to find ways to authenticate properly.
I eventually landed on using the Microsoft.Identity.Client library to require logging in via a registered Azure application. I could then cache this and refresh as needed, this way making sure the access is still valid.
However, I'm stuck on something. I have the app registration set to public with no client secrets or certificates with all of the necessary permissions. However right at the var oauth2 step, it fails while giving the error "Original exception: AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'."
The issue is that the application is public and is defined to allow public client flows. So I'm not getting how the request could still require a client secret when that's not how I'm building the request at all. I tried using private, but because of the MFA requirement, that fails too.
Below is what I have. Ignore that I'm hard coding stuff; it's temporary until I can get this sorted out. I'm also only scoping the SMTP permissions because all this application needs to do is send an email; IMAP isn't needed since it's not reading or anything else.
var options = new PublicClientApplicationOptions
{
ClientId = "[clientID]",
TenantId = "[tenandID]",
RedirectUri = "http://localhost"
};
var publicClientApplication = PublicClientApplicationBuilder
.CreateWithApplicationOptions(options)
.Build();
var scopes = new string[] {
"email",
"offline_access",
"https://outlook.office.com/SMTP.Send" // Only needed for SMTP
};
var authToken = await publicClientApplication.AcquireTokenInteractive(scopes).ExecuteAsync();
//Here is where it returns that it needs a client_secret and won't advance.
// The login window appears and states it was successfully authenticated,
// but the application crashes with that error at this step.
var oauth2 = new SaslMechanismOAuth2(Config.Env.smtpUser, authToken.AccessToken);

Authenticating HttpClient calls from .NET Core on MacOS

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.

how can authenticate a client on a different machine on a WebAPI with a user from WebAPI's domain?

I have an ASP.NET Web Api 2.2 with Windows Authentication enabled.
And also, I have a client with .NET Framework 4.0 to connect to this WebAPI:
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true
};
// Llamar al servicio web para obtener los códigos.
using (var client = new HttpClient(handler))
{
}
But the client will run in a computer that it isn't on the same domain than the web api.
Is UseDefaultCredentials = true enought or do I have to pass user, password and domain to the web service?
IIS is going to try and authenticate the HTTP request coming in using Windows Authentication and it's going to fail because the box is on a different domain. None of your server side code is going to execute. Take a look at the HTTP request/response flow in Fiddler or a browsers developer tools to understand the process of Windows Authentication better.
You could create a page on the server with anonymous access enabled which could run some authentication code but you'd need to consider how you're going to send the username and password over securely...

Connect to Exchange email with windows authentication

Its possible to connect to Exchange email box with windows authentication ? I cant have password in the program because of security compliance. If yes, how? Thank you.
working solution
download: EWS Management API 2.1
http://www.microsoft.com/en-us/download/details.aspx?id=42022
add assembly to reference: C:\Program Files (x86)\Microsoft\Exchange\Web
Services\2.1\Microsoft.Exchange.WebServices.dll
switch project to .NET framework 3.5 (im not really sure if this is a must)
code
using Microsoft.Exchange.WebServices.Data;
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.UseDefaultCredentials = true;
service.AutodiscoverUrl("username#domain.tld");
If you use ExchangeServiceBinding class from Exchange Web Services you have UseDefaultCredentials property. Setting this to true will make the authentication use the current user.

Categories