EWS Connections Issues - 401 Unauthorized - vb.net

Trying to connect to exchange 2010 SP1 using EWS & VB.Net. When i try to use autodiscovery it works just fine. The problem being is it connects to my local exchange mailbox and thats not what i need. We have a mailbox that the exchange admins set up that all the programmers can connect to (call it TestMailbox). So when i do:
exchange.AutoDiscoverUrl("TestMailbox#MyDomain.com")
It connects to my local mailbox rather than the "TestMailbox". I got the password for the TestMailbox NT account from our admin and tried all of the following:
exchange.Credentials = New WebCredentials("TestMailbox#MyDomain.com", "Password")
exchange.Credentials = New WebCredentials("TestMailbox", "Password")
exchange.Credentials = New WebCredentials("TestMailbox", "Password","MyDomain")
exchange.Credentials = New WebCredentials("MyDomain\TestMailbox", "Password")
all of them fail. Say my NT username on my local net work is "User" i even tried:
exchange.Credentials = New WebCredentials("User#MyDomain.com", "MyPassword")
and it failed. I have been using the following Link for reference.
Edit 1: i have tried all the above with NetworkCredential rather than WebCredential and it still fails.

We figured it out. TheTestMailbox & ProdMailbox domain accounts were both setup to only allow certain computer to login locally.

Related

Can't authenticate with SMTP (but IMAP works) Microsoft 365

I'm trying to create an 'automation#mydomain.com' email account, which will be used to send out email alerts from my code. Since the days of 'basic authentication' are done, I'm implementing this with 'modern authentication'. Everything is hosted in Microsoft 365. Authentication is using the latest MSAL. Email is handled using the recommended MailKit library.
The Code
This code is trying to do four things:
Read a certificate from a file.
Use that certificate to get an authentication token from Microsoft.
Test that token and the configuration by opening an IMAP connection to the desired inbox and reading out the number of messages inside.
Send an email.
Dim AuthCert = New X509Certificate2(CertPath, EmailSettings("AuthCertPassword"), X509KeyStorageFlags.PersistKeySet)
AuthClient = ConfidentialClientApplicationBuilder.Create(EmailSettings("ApplicationID")).
WithAuthority(AzureCloudInstance.AzurePublic, EmailSettings("TenantID")).
WithCertificate(AuthCert).
Build
Dim AuthResult = AuthClient.AcquireTokenForClient({"https://outlook.office365.com/.default"}).ExecuteAsync.Result
Dim EmailMessage As New MimeMessage
EmailMessage.From.Add(New MailboxAddress(Nothing, Config.EmailSenderAddress))
For Each R In Config.EmailRecipients
EmailMessage.To.Add(New MailboxAddress(Nothing, R))
Next
EmailMessage.Body = New TextPart("plain") With {.Text = Warning}
Using MailClient As New ImapClient
MailClient.Connect("outlook.office365.com", 993, SecureSocketOptions.SslOnConnect)
Log.WriteEntry($"Token length is: {AuthResult.AccessToken.Length}")
Dim Authentication As New SaslMechanismOAuth2(Config.EmailSenderAddress, AuthResult.AccessToken)
MailClient.Authenticate(Authentication)
MailClient.Inbox.Open(MailKit.FolderAccess.ReadOnly)
Log.WriteEntry($"IMAP worked. Inbox count is {MailClient.Inbox.Count}")
MailClient.Disconnect(True)
End Using
Using MailClient As New SmtpClient
MailClient.Connect("smtp.office365.com", 587, SecureSocketOptions.StartTls)
Dim Authentication As New SaslMechanismOAuth2(Config.EmailSenderAddress, AuthResult.AccessToken)
MailClient.Authenticate(Authentication)
MailClient.Send(EmailMessage)
MailClient.Disconnect(True)
End Using
The above code almost works.
Read certificate file ✔
Get a working authentication token ✔
Connect via IMAP to read number of emails in the inbox ✔
Send an email via SMTP ✖
The error message is:
MailKit.Security.AuthenticationException: 535: 5.7.3 Authentication unsuccessful [BN9PR03CA0500.namprd03.prod.outlook.com 2023-01-26T16:58:30.103Z 08DAFF3B69EFD03B]
It occurs on the line: MailClient.Authenticate(Authentication) in the Smtp section.
Note that this same exact authentication succeeded when used for IMAP.
The M365 Config
I have followed two Microsoft articles in setting up my cloud-side configuration. The first article is:
Authenticate an IMAP, POP or SMTP connection using OAuth
I have registered the application and given it the required API permissions:
I don't have to worry about the workings of SASL XOAUTH2 because the MailKit library implements that for me.
I have created the 'service principal' using the New-ServicePrincipal command (using the correct Object ID from the Enterprise Application node). And have run the Add-MailboxPermission command to grant that principal access to the mailbox.
I have also followed the steps from this article:
Enable or disable authenticated client SMTP submission (SMTP AUTH) in Exchange Online
SMTP Authorization is disabled at the organization level. But that setting has been overridden for this specific mailbox using the Set-CASMailbox command.
So, what am I missing?
It might be temporary server issue with Microsoft OAuth that is ongoing for several day now. Many many reports from ppl with different email clients report for the same issue. For example
https://support.emclient.com/index.php?/Knowledgebase/Article/View/256/7/cannot-send-emails-for-outlookcom-accounts---authentication-aborted

Remote service call through proxy

I'm trying to make a very simple service call from VS2012.
The service is on a domain outside a proxy and requires logon credentials.
I have set a refrence to the service in visuals studio. At that point i entered in the remote domian username and password and VS created all the proxy classes for me.
I then added this line to appconf file.
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="true">
</defaultProxy>
</system.net>
Which i believe will allow me to get through our proxy using my own credentails
I then wronte this simple piece of code
private void GetData()
{
OASIS.OasisServiceSoapClient o = new OASIS.OasisServiceSoapClient();
o.ClientCredentials.UserName.UserName = #"OtherDimain\UserName";
o.ClientCredentials.UserName.Password = "Password";
var d = o.SelectOfficersAll();
}
and of course it didn't work and i got all the errors that everyone has posted on.
So first question is
do i need to add this
o.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
because i did and still get that same stupid error
"The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'."
and inner exception
"{"The remote server returned an error: (401) Unauthorized."}"
so am i getting through the proxy ?
Am i using my own credentials ?
Am i passing the right paramaters in to the Service Model ?
Some examples show the username and password properties in the code above are to impersonate the current job.
But i read these on the MSDN page as being the credentials you want to use on the remote serve. The Help topic is ambigious. And if i don't enter them here then how ?
I'm trying to do something so simple , yet can't seem to get past this point.
Ok thanks to my Colleague Sean. It seems that depending on wether you are calling a web service or a WCF services determines what you need to do.
So as a web service this works
OASISWeb.OasisService s = new OASISWeb.OasisService();
s.Credentials = new System.Net.NetworkCredential("Username", "Password", "Domain");
var d = s.SelectOfficersAll();
DataSet x = (DataSet)d;
if it's a WCF service then you need this
var service = new OasisTest2.ServiceReference1.OasisServiceSoapClient();
System.Net.WebRequest.DefaultWebProxy.Credentials = system.Net.CredentialCache.DefaultNetworkCredentials;
service.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("Username", "Password", "Domain");
var result = service.SelectOfficersAll();
It seems that WebRequest is a global object and you need to set the DefaultWebProxy.Credentails on it.
How you are suppose to know that ? I never found any reference to it when i searched on how to connect to a WCF service on MSDN. Must be a secret. So keep it under your hat.

401 Unauthorized while ExchangeService.SubscribeToPushNotifications

Hi I have written an standalone Windows Forms application which uses EWS (Exchange Web Services) Managed API to listen to the new mail event on a particular email id. I am using impersonation. This is a part of my code:
service = new ExchangeService(SyncSettings.ExchangeServerVersion);
service.Credentials = new WebCredentials(userid, password);
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, impersonatedUserId);
service.Url = new Uri(exchnguri);
FolderId[] folders=new FolderId[1];
folders[0] = new FolderId(WellKnownFolderName.Inbox);
EventType[] events = new EventType[1];
events[0] = EventType.NewMail;
subscription = service.SubscribeToPushNotifications(folders, new Uri(listenUri), notificationInterval, "", events);
On Exchange Server side, I have provided one user account privileges to impersonate another user account.
When I run app in one environment it works fine. But when I run it in another it gives following error:
Immediate Stack Trace
===================================================================================
Microsoft.Exchange.WebServices.Data.ServiceRequestException : The request failed. The remote server returned an error: (401) Unauthorized.
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request)
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ValidateAndEmitRequest(IEwsHttpWebRequest& request)
at Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.Execute()
at Microsoft.Exchange.WebServices.Data.ExchangeService.SubscribeToPushNotifications(IEnumerable`1 folderIds, Uri url, Int32 frequency, String watermark, EventType[] eventTypes)
at com.org.app.Class.startListeningPushNotifications(String listenUri, Int32 notificationInterval) in c:\SW\app\Class.cs:line 156
Inner Exception 1 : Stack Trace
-----------------------------------------------------------------------------
System.Net.WebException . The remote server returned an error: (401) Unauthorized.
at System.Net.HttpWebRequest.GetResponse()
at Microsoft.Exchange.WebServices.Data.EwsHttpWebRequest.Microsoft.Exchange.WebServices.Data.IEwsHttpWebRequest.GetResponse()
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request)
The only difference I observe in two environments is:
In first environment I login owa (Outlook Web Access) using domainx\userx, and to send mail to self account (that is, to the account with which I have logged in) I put userx#domainx.com in to field
However in second environment I login owa using domainxdc\userx (notice 'dc' in domainxdc), and send self mail with userx#domainx.com in to field. (notice no 'dc' in domainx.com)
I dont think that is giving me 401 Unauthorised, since I can login to owa using both impersonating and impersonated account. And I have given impersonating privileges in 2nd environment in exactly the same way as in 1st environment.
So why I am getting 401 Unauthorised ?
We are using Exchange Server 2007 and Windows Server 2008 SP2.
Here's something to try--might work:
service.CookieContainer = new CookieContainer();
I'm not very clear on why this helps, and in my case, it was going against Exchange Online, not your on-prem E2007. Might help; can't hurt. There was a blog post on this, but not sure if this will apply to your case.

PowerShell send SMTP email without (default) authentication

I am attempting to deliver an email to an Exchange-server using PowerShell. My goal is to use plain old SMTP to deliver a message to a local user (mailbox) on the Exchange-server. The Exchange-server is located within the same network and AD-domain as the sending server and as the logged on sending user.
However the user I am sending from does not have access to send emails on that Exchange-server. And PowerShell seems to send authentication using the logged on user credentials by default.
$smtp = new-object Net.Mail.SmtpClient("exchangeserver.mylan")
$smtp.Send($emailFrom, $emailTo, $subject, $message)
I have tried to add $smtp.UseDefaultCredentials = $false before the $smtp.Send(... line without success.
One solution would be to allow this user to send messages on the Exchange server. However the user will change depending on what service is running this script, so I don't want to solve it that way.
Another solution would be to hardcode credentials using something like $smtp.Credentials = New-Object System.Net.NetworkCredential("DOMAIN\user", "password") (also before $smtp.Send(... line). I've had no luck in this either.
The solution I'd really like is to just send email in PowerShell anonymously using good old auth free SMTP.
1) Create new Receive Connector
2) Enable anonymous authentication on it
3) Lock it down to IP address of the computer you are running the script on
I realize this is old, but I'm surprised there isn't an answer here for this. I was confused initially because I have some similar code I wrote in C# and it works just fine. It seems PowerShell will default to using someone's credentials. I won't assume it's who runs the script, but it could be.
When I'm building up the credential object, I pass in a space for the username and password and that seems to work fine.
$credential = New-Object System.Management.Automation.PSCredential (" ", " ")
If I completely leave out the credential part then it will use someone's credentials or something. Until now I was getting the following message:
The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.1 Client was not authenticated
I hope this helps someone with such an odd problem.

Dynamics CRM - Caller not authenticated to service

I have an MVC4 Web Application on Web Server A that is consuming the Dynamics CRM Web Service using the OrganizationServiceProxy, which is on Web Server B. The MVC4 application is setup with ASP .NET Impersonation and Windows Authentication enabled. When I call the WhoAmI I get an error:
'The caller was not authenticated by the service.'
Now if I move the MVC4 Application to Web Server B (same as CRM) with the same Authentication as it had on Web Server A it calls WhoAmI without an exception.
Here is the code being used to connect to the server.
string serviceURL = ConfigurationManager.AppSettings["CRMROOTURL"].ToString() + "XRMServices/2011/Organization.svc";
this.CRMService = GetCRMService(serviceURL);
private OrganizationServiceProxy GetCRMService(string serviceURL)
{
ClientCredentials credentials = new ClientCredentials();
credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
OrganizationServiceProxy client
= new OrganizationServiceProxy(new Uri(serviceURL), null, credentials, null);
return client;
}
Here is a screenshot of the authentication on the IIS Web Site.
Per the correct answer I just wanted to provide some snippets to help anyone else.
string loggedUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
ClientCredentials credentials = new ClientCredentials();
credentials.Windows.ClientCredential = new NetworkCredential(username, password, domain);
OrganizationServiceProxy client
= new OrganizationServiceProxy(new Uri(serviceURL), null, credentials, null);
client.ClientCredentials.Windows.ClientCredential = credentials.Windows.ClientCredential;
// -- Retrieve the user.
QueryExpression expression = new QueryExpression
{
EntityName = "systemuser",
ColumnSet = new ColumnSet("systemuserid")
};
expression.Criteria.AddCondition("domainname", ConditionOperator.Equal, loggedUser);
EntityCollection ec = client.RetrieveMultiple(expression);
if (ec.Entities.Count > 0)
{
// -- Impersonate the logged in user.
client.CallerId = ec.Entities[0].Id;
}
Thanks!
Unless you explicitly state otherwise (and without any code to see how you are creating your OrganizationServiceProxy), on premise OrganizationServiceProxies will use the current AD account (of the service account, not the user's specific account) to connect to CRM. I'm guessing that the App pool you're running on Server A isn't a CRM user, and the one on Server B is. If so, either change Server A's user to be the same user as Server B, or make the Server A's user a user in CRM.
Edit
You're using the default network credentials to connect to CRM. This mean that no matter what IIS authentication you are using, you will connect to CRM as the App Pool User Account. This works as long as the App Pool user is a CRM user, but is probably not what you want.
You can set the network credential manually using this method:
creds.Windows.ClientCredential = new System.Net.NetworkCredential("UserId", "Password", "DomainName");
Then get the ASP.Net User's domain name and use impersonation to connect to CRM to ensure that all of the security for that individual is correctly applied.
Something stupid - be careful you aren't escaping your user name!
creds.Windows.ClientCredential = new NetworkCredential("domain\user", "PASSWORD");
Notice that the \u is an escape sequence - you need to type "domain\user".