EWS Managed API Double Hop
Я занимаюсь разработкой интранет-сайта, который будет использоваться на месте. В корпоративной среде пользователи могут использовать этот сайт, например OWA, они могут видеть свои входящие сообщения, отправлять почту и т. Д. Для этого я использую EWS Managed Api 2.2 для подключения к Exchange Server (2010_sp1). Я занимаюсь разработкой с ASPNet MVC 5. Я занимаюсь разработкой на своем компьютер с установленным IIS 10.0. Пока я разрабатывал с IISExpress, не было проблем с подключением с учетными данными по умолчанию>
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
service.UseDefaultCredentials = true;
Я понимаю, что это потому, что IIS Express использует мои учетные данные в качестве учетных данных по умолчанию, поэтому не было ошибок при подключении службы. Но когда я запускаю этот код с IIS на моем компьютере (с моими учетными данными в идентификаторе пула приложений, с использованием олицетворения ASPNet, включенной аутентификации Windows и провайдеров NEGOTIATE/NTML), загрузка выполняется корректно
HttpContext.User.Identity.Name > xxx\billgates
WindowsIdentity.GetCurrent().Name> xxx\billgates
но служба Exchange возвращает в след эти>
<Trace Tag="EwsRequestHttpHeaders" Tid="29" Time="2017-01-02 08:03:04Z">
POST /EWS/Exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
User-Agent: ExchangeServicesClient/15.00.0913.015
Accept-Encoding: gzip,deflate
</Trace>
<Trace Tag="EwsRequest" Tid="29" Time="2017-01-02 08:03:04Z" Version="15.00.0913.015">
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<t:RequestServerVersion Version="Exchange2010_SP1" />
</soap:Header>
<soap:Body>
<m:GetFolder>
<m:FolderShape>
<t:BaseShape>AllProperties</t:BaseShape>
</m:FolderShape>
<m:FolderIds>
<t:DistinguishedFolderId Id="inbox" />
</m:FolderIds>
</m:GetFolder>
</soap:Body>
</soap:Envelope>
</Trace>
<Trace Tag="EwsResponseHttpHeaders" Tid="29" Time="2017-01-02 08:03:04Z">
HTTP/1.1 401 Unauthorized
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate,NTLM
X-Powered-By: ASP.NET
Date: Mon, 02 Jan 2017 08:03:04 GMT
Content-Length: 0
</Trace>
Когда я использую EWEditor ( https://ewseditor.codeplex.com/), я обнаружил, что нет ошибки при соединении с учетными данными по умолчанию, и при запуске klist в powershell присутствуют галочки Kerberos, например>
Сервер: krbtgt/xxxxx.xxx.xx@xxxxx.xxx.xx Тип шифрования KerbTicket: RSADSI RC4-HMAC(NT) Время окончания: 1/2/2017 21:35:37 Время обновления: 09.01.2017 11:35:37
Сервер: krbtgt/xxxxx.xxx.xx@xxxxx.xxx.xx Тип шифрования KerbTicket: Неизвестно (18) Время окончания: 1/2/2017 21:35:37 Время обновления: 01.01.2017 11:35:37
Сервер: HTTP/posta.xxxxx.xxx.xx@xxxxx.xxx.xx Тип шифрования KerbTicket: RSADSI RC4-HMAC(NT) Время окончания: 1/2/2017 21:35:37 Время обновления: 09.01.2017 11: 35: 37
Сервер: HTTP/autodiscover.xxxxx.xxx.xx@xxxxx.xxx.xx Тип шифрования KerbTicket: RSADSI RC4-HMAC(NT) Время окончания: 1/2/2017 21:35:37 Время обновления: 09.01.2017 11: 35: 37
Сервер: HTTP/xxxcas2.xxxxx.xxx.xx@xxxxx.xxx.xx Тип шифрования KerbTicket: Неизвестно (18) Время окончания: 1/2/2017 21:35:37 Время обновления: 09.01.2017 11:35:37
Сервер: ldap/xxxDC2.xxxxx.xxx.xx@xxxxx.xxx.xx Тип шифрования KerbTicket: Неизвестно (18) Время окончания: 1/2/2017 21:35:37 Время обновления: 09.01.2017 11:35:37
с этими билетами я предполагаю, что kerberos работает, мой первый вопрос: я прав? Могу ли я быть уверен, что эти билеты гарантируют, что keberos работает с серверами клиентского доступа?
Во время поиска этой проблемы я обнаружил, что эта проблема очень похожа на проблему двойного прыжка, как в этом блоге говорится> https://blogs.msdn.microsoft.com/dhruvkh/2012/04/15/the-double-hop-dogma/ Фактически моя проблема точно так же, как этот пост. Как и в этом посте, я рекомендую использовать свою учетную запись в качестве служебной учетной записи, добавить SPNS в свою учетную запись и указать это в идентификаторе пула приложений в IIS.
SPN, которые я использовал
HTTP /autodiscover.xxxxxx.xxx.xx
HTTP / posta.xxxxxx.xxx.xx
ПРИМЕЧАНИЕ. Я уверен, что эти SPN не использовались.
После добавления spns я также проверяю "Доверять этот компьютер для делегирования любой службе (только Kerberos)". на вкладке Делегация моей учетной записи.
Мой другой вопрос заключается в том, что, как и в сообщении, предлагается на 3. шаг https://technet.microsoft.com/en-us/library/ff808312(v=exchg.141).aspx если я должен создать альтернативную учетную запись службы вместо использования моей учетной записи? Если мне нужно использовать ASA, я должен добавить учетные данные альтернативной учетной записи службы в удостоверение пула приложений IIS?
Спасибо за помощь.
1 ответ
Обновление из предыдущего поста. Я заставил это работать, и мои текущие настройки не соответствуют ожиданиям. Я использую IIS 8.5 на Win 2012 R2
- AppPool: настроен на интегрированный конвейер
- AppPool: Загрузить профиль пользователя: False
- AppPool: IIS работает под учетной записью службы домена, настроенной для делегирования
- В приложении> Аутентификация. ASP.Net Олицетворение: Отключено. Аутентификация Windows: включен с режимом ядра выключен. Провайдеры: переговоры: Keberos.
- Редактор конфигурации> system.webServer / security / authentication / windowsAuthentication useAppPoolCredentials: True. useKernelMode: False
- Локальная политика безопасности> Локальные политики> Назначение прав пользователя: учетная запись службы должна находиться в группе, указанной в политике "Олицетворять клиента после проверки подлинности".
Модификация к Aspnet.config (C:\Windows\Microsoft.NET\Framework64\v4.0.30319)
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="false" />
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
<SymbolReadingPolicy enabled="1" />
<shadowCopyVerifyByTimestamp enabled="true"/>
</runtime>
<startup useLegacyV2RuntimeActivationPolicy="true" />
</configuration>
Ниже приведен источник службы, который работает. Я оставил весь закомментированный код, чтобы вы могли видеть все, что я пробовал. Обратите внимание, что требуется только часть активного кода.
//using(HostingEnvironment.Impersonate())
//{
try
{
//DC = new PrincipalContext(ContextType.Domain, myDomain);
//GP = GroupPrincipal.FindByIdentity(DC, IdentityType.Name, Constant.QMS_GROUP_PRINCIPAL);
//ImpersonationContext = ((System.Security.Principal.WindowsIdentity)System.Threading.Thread.CurrentPrincipal.Identity).Impersonate();
//the service creation gets called regularly and
//autodiscovery is very slow
if(PerformanceHelper.GetMailService() != null)
{
return PerformanceHelper.GetMailService();
}
//create a service
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.TraceListener = new TraceListener();
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.CookieContainer = new CookieContainer(1);
service.PreAuthenticate = true;
//CredentialCache credCache = new CredentialCache();
//credCache.Add(new Uri(Constant.QMS_EXCHANGE_SVC), "Negotiate",
// CredentialCache.DefaultNetworkCredentials);
//HttpWebRequest req = (HttpWebRequest)WebRequest.Create(new Uri(Constant.QMS_EXCHANGE_SVC));
//req.Credentials = credCache;
//service.Credentials = credCache.GetCredential(new Uri(Constant.QMS_EXCHANGE_SVC), "Negotiate");
NetworkCredential nc = new NetworkCredential();
nc = CredentialCache.DefaultNetworkCredentials;
//nc = (NetworkCredential)CredentialCache.DefaultCredentials;
service.Credentials = nc;
ErrorHelper.AddErrorMsg("makeExchangeConnection IsWindowsIdentityFlowSuppressed() (info): "
+ Convert.ToString(System.Security.SecurityContext.IsWindowsIdentityFlowSuppressed()));
//WebCredentials wc = new WebCredentials(System.Net.CredentialCache.DefaultCredentials);
//WebCredentials wc = new WebCredentials(System.Net.CredentialCache.DefaultCredentials);
//service.Credentials = wc;
ErrorHelper.AddErrorMsg("makeExchangeConnection (info): " + System.Threading.Thread.CurrentPrincipal.Identity.Name);
//use the windows login credential
service.UseDefaultCredentials = true;
//the autodiscovery has been failing in dev.
//the catch should rescue the connetcion.
//I'm disabling this for now and just
//declaring the service via constant. The failing
//auto discover is a big performance hit
//especially since it can't work behind the
//firewall
//try
//{
// service.AutodiscoverUrl(eMailAddress, redirectionUrlValidationCallback);
//}
//catch
//{
// service.Url = new Uri(Constant.QMS_EXCHANGE_SVC);
//}
service.Url = new Uri(Constant.QMS_EXCHANGE_SVC);
/* 01/6/2017 Enable below to allow for impersonation on
* on the exchange server. This is pending an exchange
* adminstrator granting access for the service accounts.
*/
//if(ui.Email != null)
// service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, ui.Email);
//cache the service
PerformanceHelper.AddMailService(service);
return service;
}
При вызове API сервера Exchange оберните в блок олицетворения.
public bool SendReply(string messageId, string response){
UserInfoHelper ui = new UserInfoHelper();
using(HostingEnvironment.Impersonate())
{
try
{
DC = new PrincipalContext(ContextType.Domain, Constant.QMS_DOMAIN);
GP = GroupPrincipal.FindByIdentity(DC, IdentityType.Name, "Domain Users");
ImpersonationContext = ((System.Security.Principal.WindowsIdentity)System.Threading.Thread.CurrentPrincipal.Identity).Impersonate();
//do stuff
}
catch(Exception e)
{
ErrorHelper.AddErrorMsg("SendReply: " + e);
}
}
return false;
}
Наконец, и это важно, клиентские браузеры должны быть настроены для делегирования на клиентских компьютерах. В Chrome вам нужно отредактировать реестр. В FF вам нужно настроить ключи Uris в about:config. Поведение "из коробки" завершится неудачно с Kerberos. См. Это для получения дополнительной информации ( https://answers.laserfiche.com/questions/50123/Does-single-sign-on-or-authentication-negotiation-not-work-on-Chrome-in-Weblink и https://dev.chromium.org/administrators/policy-list-3).
Ниже был мой оригинальный пост.
Я долго устранял одну и ту же проблему. Взгляните на это ( Невозможно пройти аутентификацию в ASP.NET Web Api с помощью HttpClient). Я изменил файл Aspnet.config безрезультатно. Из того, что я читал до сих пор, похоже, что System.Net.HttpWebRequest.GetResponse() находится в новом потоке, и олицетворенные учетные данные не передаются в новый объект. Я установил провайдер аутентификации IIS для согласования:kerberos, чтобы убедиться, что делегирование должно / может произойти.
я должен создать альтернативную учетную запись службы вместо использования моей учетной записи?
В зависимости от конфигурации, т. Е. IIS находится за балансировщиком нагрузки и брандмауэром, вам может потребоваться настраиваемая учетная запись службы, например mydomain\my_service_account, для которой потребуется SPN http/my.webserver.com. Тем не менее, я настроил это, и не секретный соус делает эту работу. Я начинаю думать, что единственный способ, которым это может работать, - настроить олицетворение для учетной записи Exchange ( https://msdn.microsoft.com/en-us/library/office/dn722376(v=exchg.150).aspx). В соответствии с этим планом вы бы назвали что-то вроде ниже при настройке службы. Если учетная запись службы в IIS не имеет права выдавать себя за сервер Exchange, это также не будет работать. Также вам нужно передать идентификационную информацию учетной записи службы, а не идентификацию пользователя.
if(UserInfo.Email != null)
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, UserInfo.Email);
Я надеюсь, что кто-то может дать гораздо лучший ответ, чем этот. Ниже то, что я сейчас вижу в своем следе.
9:
Трассировка>
10: GetUnreadMail ee: Microsoft.Exchange.WebServices.Data.ServiceRequestException: запрос не выполнен. Удаленный сервер возвратил ошибку: (401) Несанкционированный. ---> System.Net.WebException: удаленный сервер возвратил ошибку: (401) не авторизован. в System.Net.HttpWebRequest.GetResponse() в Microsoft.Exchange.WebServices.Data.EwsHttpWebRequest.Microsoft.Exchange.WebServices.Data.IEwsHttpWebRequest.GetResponse() в Microsoft.Exest.WebSerp_WebWerWebService.Eb --- Конец трассировки стека внутренней исключительной ситуации --- в Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(запрос IEwsHttpWebRequest) в Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ValidateAndEmitRequest.ebs.Web).Data.MultiResponseServiceRequest`1.Execute() в Microsoft.Exchange.WebServices.Data.ExchangeService.FindItems(FolderId parentFolderId, SearchFilter searchFilter, представление ViewBase) в Microsoft.Exchange.WebServices.Data.ExchangeSerFidForm IDFF, Представление ViewBase) в QDoc.Helpers.ExchangeHelper.GetUnreadMail(ExchangeParam ExchangeQueryParam, MailItemList ExchangeResults, строка myDomain) в c:\Inet\QDoc\QDoc\Helpers\ExchangeHelper.cs: строка 186