"UseDefaultCredentials" 设置为 True 时出现“401 Unauthorized”错误
I get "401 Unauthorized" error when "UseDefaultCredentials" is set to True
当我在 WebCredentials 的调用中指定用户名和密码时,我对 EWS 的调用工作正常。如果我将 ExchangeService.UseDefaultCredentials 属性 设置为 True,则会收到 401 Unauthorized 错误。
我不知道这是否重要,但我们的 Exchange 管理员告诉我,我在混合环境中工作。我们 运行 Exchange Online 和 Exchange 2010(我认为是 2013)。
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("user@company.com", "password")"
// Then Everything works fine.
//------------------------------------------------
_service.UseDefaultCredentials = true;
//_service.Credentials = new WebCredentials("user@company.com", "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, "delegator@company.com"), 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;
}
}
}
}
我们的用户帐户在 Exchange Online 上。这就是为什么将 UseDefaultCredentials 设置为 True 无效的原因。
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.
如果您的邮箱在 Office365 上,那么我建议您改用 Oauth。由于明年 EWS https://blogs.technet.microsoft.com/exchange/2018/07/03/upcoming-changes-to-exchange-web-services-ews-api-for-office-365/ 的基本身份验证将消失。
如果您使用 oAuth,那么您可以使用 windows 集成 Auth 与 ADAL 库 https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/AcquireTokenSilentAsync-using-Integrated-authentication-on-Windows-(Kerberos) 来利用当前登录的用户。
当我在 WebCredentials 的调用中指定用户名和密码时,我对 EWS 的调用工作正常。如果我将 ExchangeService.UseDefaultCredentials 属性 设置为 True,则会收到 401 Unauthorized 错误。
我不知道这是否重要,但我们的 Exchange 管理员告诉我,我在混合环境中工作。我们 运行 Exchange Online 和 Exchange 2010(我认为是 2013)。
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("user@company.com", "password")"
// Then Everything works fine.
//------------------------------------------------
_service.UseDefaultCredentials = true;
//_service.Credentials = new WebCredentials("user@company.com", "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, "delegator@company.com"), 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;
}
}
}
}
我们的用户帐户在 Exchange Online 上。这就是为什么将 UseDefaultCredentials 设置为 True 无效的原因。
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.
如果您的邮箱在 Office365 上,那么我建议您改用 Oauth。由于明年 EWS https://blogs.technet.microsoft.com/exchange/2018/07/03/upcoming-changes-to-exchange-web-services-ews-api-for-office-365/ 的基本身份验证将消失。
如果您使用 oAuth,那么您可以使用 windows 集成 Auth 与 ADAL 库 https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/AcquireTokenSilentAsync-using-Integrated-authentication-on-Windows-(Kerberos) 来利用当前登录的用户。