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

  1. AppPool: настроен на интегрированный конвейер
  2. AppPool: Загрузить профиль пользователя: False
  3. AppPool: IIS работает под учетной записью службы домена, настроенной для делегирования
  4. В приложении> Аутентификация. ASP.Net Олицетворение: Отключено. Аутентификация Windows: включен с режимом ядра выключен. Провайдеры: переговоры: Keberos.
  5. Редактор конфигурации> system.webServer / security / authentication / windowsAuthentication useAppPoolCredentials: True. useKernelMode: False
  6. Локальная политика безопасности> Локальные политики> Назначение прав пользователя: учетная запись службы должна находиться в группе, указанной в политике "Олицетворять клиента после проверки подлинности".

Модификация к 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).

Модификация реестра для Chrome

Ниже был мой оригинальный пост.

Я долго устранял одну и ту же проблему. Взгляните на это ( Невозможно пройти аутентификацию в 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: HTTP / 1.1 401 Несанкционированный сервер: Microsoft-IIS/7.5 WWW-Authenticate: согласование,NTLM X- Работает на: ASP.NET Дата: Пт, 20 января 2017 20:59:29 GMT Контент-длина: 0

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

Другие вопросы по тегам