0
votes

When I specify username and password in the call in WebCredentials my calls to EWS work fine. If I set the ExchangeService.UseDefaultCredentials property to True, then I get the 401 Unauthorized error.

I don't know if this is important, but our Exchange admin tells me that I'm working in a hybrid environment. We are running both Exchange Online, and Exchange 2010 (or 2013, I think).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Exchange.WebServices.Data;
using System.Security.Cryptography.X509Certificates;
using System.Net; 

namespace EWSLib
{
    class Program
    {
        static ExchangeService _service;
        static void Main(string[] args)
        {
            string defaultEmail = System.DirectoryServices.AccountManagement.UserPrincipal.Current.EmailAddress;            
            ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;


            try
            {
                _service = new ExchangeService();

                Appointment meeting = new Appointment(_service);

                //-----------------------------------------------
                // If I comment out
                // "_service.UseDefaultCredentials = true" 
                // and uncomment the line "_service.Credentials = new WebCredentials("[email protected]", "password")"
                // Then Everything works fine.
                //------------------------------------------------
                _service.UseDefaultCredentials = true;
                //_service.Credentials = new WebCredentials("[email protected]", "password");


                _service.TraceEnabled = true;
                _service.TraceFlags = TraceFlags.All;
                //_service.AutodiscoverUrl(defaultEmail, RedirectionUrlValidationCallback);
                _service.Url = new Uri("https://example.com/EWS/Exchange.asmx");

                // TEST MEETING
                meeting.Subject = "The subject";
                meeting.Body = "The boddy";
                meeting.Start = DateTime.UtcNow.AddDays(5);
                meeting.End = DateTime.UtcNow.AddDays(5).AddHours(1);
                meeting.Location = "Someplace";
                meeting.IsReminderSet = true;



                meeting.RequiredAttendees.Add(defaultEmail);
                meeting.ReminderMinutesBeforeStart = 60;


                // Delegation
                meeting.Save(new FolderId(WellKnownFolderName.Calendar, "[email protected]"), SendInvitationsMode.SendToAllAndSaveCopy);



                // Verify that the meeting was created.
                Item item = Item.Bind(_service, meeting.Id, new PropertySet(ItemSchema.Subject));




            }
            catch (Exception e)
            {
                //System.Diagnostics.Debug.WriteLine(e);
                Console.WriteLine(e);
            }

            Console.ReadLine();
        }

        private static bool RedirectionUrlValidationCallback(string redirectionUrl)
        {
            // The default for the validation callback is to reject the URL.
            bool result = false;
            Uri redirectionUri = new Uri(redirectionUrl);
            // Validate the contents of the redirection URL. In this simple validation
            // callback, the redirection URL is considered valid if it is using HTTPS
            // to encrypt the authentication credentials. 
            if (redirectionUri.Scheme == "https")
            {


                result = true;
            }
            return result;
        }

        private static bool CertificateValidationCallBack(
    object sender,
        System.Security.Cryptography.X509Certificates.X509Certificate certificate,
    System.Security.Cryptography.X509Certificates.X509Chain chain,
    System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            // If the certificate is a valid, signed certificate, return true.
            if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
            {
                Console.WriteLine("Valid Signed Certificate");
                return true;
            }

            // If there are errors in the certificate chain, look at each error to determine the cause.
            if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
            {
                if (chain != null && chain.ChainStatus != null)
                {
                    foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
                    {
                        if ((certificate.Subject == certificate.Issuer) &&
                       (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                        {
                        // Self-signed certificates with an untrusted root are valid. 
                            Console.WriteLine("Self-signed certificates with an untrusted root are valid.");
                            continue;
                        }
                        else
                        {
                            if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                            {
                                // If there are any other errors in the certificate chain, the certificate is invalid,
                                // so the method returns false.
                                Console.WriteLine("there are any other errors in the certificate chain");
                                return false;
                            }
                        }
                    }
                }

                // When processing reaches this line, the only errors in the certificate chain are 
                // untrusted root errors for self-signed certificates. These certificates are valid
                // for default Exchange server installations, so return true.
                Console.WriteLine("Valid for some reason");
                return true;
            }
            else
            {
                // In all other cases, return false.
                Console.WriteLine("there are any other errors in the certificate chain");
                return false;
            }
        }
    }
}
2

2 Answers

1
votes

If your mailboxes are on Office365 then I would suggest you use Oauth instead. As basic auth is going away next year for EWS https://blogs.technet.microsoft.com/exchange/2018/07/03/upcoming-changes-to-exchange-web-services-ews-api-for-office-365/ .

If you use oAuth then you can use windows integrated Auth with the ADAL library https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/AcquireTokenSilentAsync-using-Integrated-authentication-on-Windows-(Kerberos) to take advantage for the currently logged on user.

0
votes

Our user accounts are on Exchange Online. This is why setting the UseDefaultCredentials to True has no effect.

From Microsoft

You cannot use the default credentials of the logged on user if the user’s mailbox is hosted in Exchange Online or Exchange Online as part of Office 365. Instead, use the Credentials property to set the user’s credentials. The user’s credentials must be in user principal name (UPN) form for Exchange Online.