Доступ к почтовому ящику имперсонифицированного пользователя в Exchange Online

В предыдущих статьях (см. перечень в Использование EWS managed API v.2.0) была зарегистрирована учетная запись в Office 365 для компании Example Company и настроена имперсонификация пользователей. В данной заметке рассмотрим код программы на C#, которая с помощью EWS подключается к Exchange Online под пользователем Mail Admin и выполняет манипуляции с почтовыми ящиками других пользователей. Напомним, что пользователь Mail Admin имеет право импресонифицировать пользователей First User и Second User.

Для работы программы требуется, чтобы EWS 2.0 был проинсталлирован на компьютере. Кроме того, пароль Qwerty123 нужно заменить на настоящий.

В методе CreateService создается объект ExchangeService для подключения под указанным пользователем. Поскольку используется автоопределение реального адреса сервиса, который отличается для различных датацентров, требуется определить метод RedirectionUrlValidationCallback, где анализируется предполагаемый адрес переадресации, после чего разрешается или запрещается переадресация. Домен можно не указывать либо использовать ExampleCompany.onmicrosoft.com. Затем для каждого зарегистрированного в домене пользователя вызывается метод имперсонификации SetImpersonatedUser и выполняется доступ к почтовому ящику.

В следующем методе, PageThroughEntireInbox, перебираются сообщения из почтового ящика пользователя, загружается их содержимое и основные свойства, и в консоль выводится описание писем. Предварительно было отправлено несколько тестовых писем в текстовом и HTML формате.

#region

using System;
using System.Linq;
using System.Net;
using Microsoft.Exchange.WebServices.Autodiscover;
using Microsoft.Exchange.WebServices.Data;

#endregion

namespace Office365Impersonation
{
  internal static class Program
  {
    static void Main(string[] args)
    {
      // создать сервис
      var service = CreateService(
        @"Mail.Admin@ExampleCompany.onmicrosoft.com",
        "Qwerty123",
        null,
        @"Mail.Admin@ExampleCompany.onmicrosoft.com");

      var users = new[]
        {
          "First.User@ExampleCompany.onmicrosoft.com",
          "Second.User@ExampleCompany.onmicrosoft.com",
          "Third.User@ExampleCompany.onmicrosoft.com",
          "Fourth.User@ExampleCompany.onmicrosoft.com",
          "Mail.Admin@ExampleCompany.onmicrosoft.com"
        };

      // перебрать ящики пользователей
      foreach (var user in users)
      {
        Console.WriteLine("\n*** Testing user '{0}' ***\n", user);
        SetImpersonatedUser(service, user);
        // перебрать почтовые сообщения
        PageThroughEntireInbox(service);
      }
      Console.ReadKey();
    }

    static ExchangeService CreateService(
      string userName,
      string password,
      string domain,
      string autodiscoverAddress)
    {
      // подключение к Exchange сервису
      var service = new ExchangeService(ExchangeVersion.Exchange2013)
        {
          Credentials = new NetworkCredential(
            userName,
            password,
            domain)
        };

      const string autodiscoverUrl =
        @"https://outlook.office365.com/EWS/Exchange.asmx";
      try
      {
        service.AutodiscoverUrl(
          autodiscoverAddress,
          RedirectionUrlValidationCallback);
      }
      catch (AutodiscoverRemoteException ex)
      {
        Console.WriteLine("Exception is thrown: " + ex.Error.Message);
        service.Url = new Uri(autodiscoverUrl);
      }
      catch (AutodiscoverLocalException ex)
      {
        Console.WriteLine("Exception is thrown: " + ex.Message);
        service.Url = new Uri(autodiscoverUrl);
      }
      Console.WriteLine(service.Url);
      return service;
    }

    static bool RedirectionUrlValidationCallback(String redirectionUrl)
    {
      // допускаем все переадресации
      return true;
    }

    static void SetImpersonatedUser(
      ExchangeService service,
      string userAddress)
    {
      if (service == null || string.IsNullOrWhiteSpace(userAddress))
        return;
      userAddress = userAddress.Trim(' ', '\t', ',', ';', '.');
      service.ImpersonatedUserId = new ImpersonatedUserId(
        (userAddress.IndexOf('@') > 0) ?
          ConnectingIdType.SmtpAddress :
          ConnectingIdType.PrincipalName,
        userAddress);
    }

    static void PageThroughEntireInbox(ExchangeService service)
    {
      var view = new ItemView(50);
      try
      {
        FindItemsResults findResults;
        do
        {
          findResults = service.FindItems(WellKnownFolderName.Inbox, view);

          var current = 0;
          foreach (var item in findResults.Items)
          {
            var message = item as EmailMessage;
            if (message == null)
              continue;

            // загрузка свойств письма
            message.Load(new PropertySet(
              BasePropertySet.FirstClassProperties));
            // информационная строка с описанием письма
            Console.WriteLine("Email #{1}{0}Subject:{2}{0}From:\t{3}{0}To:\t{4}{0}Send:\t{5}{0}Get:\t{6}{0}Body ({7}):{0}{8}",
                      Environment.NewLine,
                      ++current,
                      message.Subject,
                      message.From,
                      String.Join(
                        String.Format("{0}\t", Environment.NewLine),
                        message.ToRecipients.Select(
                          address => address.ToString())),
                      message.DateTimeSent.ToShortDateString() + " " +
                      message.DateTimeSent.ToShortTimeString(),
                      message.DateTimeReceived.ToShortDateString() + " " +
                      message.DateTimeReceived.ToShortTimeString(),
                      message.Body.BodyType,
                      message.Body.Text);
          }
          view.Offset += 50;
        } while (findResults.MoreAvailable);
      }
      catch (ServiceResponseException ex)
      {
        Console.WriteLine("Exception is thrown: " + ex.Message);
      }
    }
  }
}

Приложение выводит следующую информацию:
*********************** Console – Begin ************************
https://outlook.office365.com/EWS/Exchange.asmx

*** Testing user ‘First.User@ExampleCompany.onmicrosoft.com’ ***

Email #1
Subject: The plain text test e-mail
From:   Illya Reznykov <SMTP:ireznykov@hotmail.com>
To:     First User <SMTP:First.User@ExampleCompany.onmicrosoft.com>
Send:   11.01.2014 12:48
Get:    11.01.2014 12:50
Body (Text):
Hi User,

This is a plain text message, and sent in order to test EWS access to user’s
mailbox.

Sincerely,
Illya Reznykov

Email #2
Subject: The test e-mail
From:   Owner Account <SMTP:Owner.Account@ExampleCompany.onmicrosoft.com>
To:     First User <SMTP:First.User@ExampleCompany.onmicrosoft.com>
        Second User <SMTP:Second.User@ExampleCompany.onmicrosoft.com>
        Third User <SMTP:Third.User@ExampleCompany.onmicrosoft.com>
        Fourth User <SMTP:Fourth.User@ExampleCompany.onmicrosoft.com>
        Mail Admin <SMTP:Mail.Admin@ExampleCompany.onmicrosoft.com>
Send:   11.01.2014 12:20
Get:    11.01.2014 12:20
Body (HTML):
<html tabindex=”-1″ style=”-ms-scrollbar-base-color: rgb(0, 0, 0); -ms-scrollbar-face-color: rgb(240, 240, 240); -ms-scrollbar-3dlight-color: rgb(227, 227, 227); -ms-scrollbar-shadow-color: rgb(160, 160, 160); -ms-scrollbar-highlight-color: rgb(255, 255, 255); -ms-scrollbar-darkshadow-color: rgb(105, 105, 105); -ms-scrollbar-arrow-color: rgb(0, 0, 0);”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″>
<meta http-equiv=”X-UA-Compatible” content=”IE=10″>
<meta name=”GENERATOR” content=”MSHTML 11.00.9600.16428″>
<style id=”owaParaStyle” style=”display: none;”><!–P {margin-top:0;margin-bottom:0;}–></style>
</head>
<body tabindex=”0″ style=”” dir=”ltr” aria-label=”Message body” fPStyle=”1″>
<div name=”divtagdefaultwrapper” id=”divtagdefaultwrapper” style=”font-family: Calibri,Arial,Helvetica,sans-serif; font-size: 12pt; color: #000000; margin: 0″>
<p>Hi all,</p>
<p> </p>
<p>This message is used for testing EWS access to user’s mailbox.</p>
<p> </p>
<p>Regards,</p>
<p>Owner Account</p>
<p> </p>
</div>
</body>
</html>

*** Testing user ‘Second.User@ExampleCompany.onmicrosoft.com’ ***

Email #1
Subject: The plain text test e-mail
From:   Illya Reznykov <SMTP:ireznykov@hotmail.com>
To:     Second User <SMTP:Second.User@ExampleCompany.onmicrosoft.com>
Send:   11.01.2014 12:49
Get:    11.01.2014 12:51
Body (Text):
Hi User,

This is a plain text message, and sent in order to test EWS access to user’s
mailbox.

Sincerely,
Illya Reznykov

Email #2
Subject: The test e-mail
From:   Owner Account <SMTP:Owner.Account@ExampleCompany.onmicrosoft.com>
To:     First User <SMTP:First.User@ExampleCompany.onmicrosoft.com>
        Second User <SMTP:Second.User@ExampleCompany.onmicrosoft.com>
        Third User <SMTP:Third.User@ExampleCompany.onmicrosoft.com>
        Fourth User <SMTP:Fourth.User@ExampleCompany.onmicrosoft.com>
        Mail Admin <SMTP:Mail.Admin@ExampleCompany.onmicrosoft.com>
Send:   11.01.2014 12:20
Get:    11.01.2014 12:20
Body (HTML):
<html tabindex=”-1″ style=”-ms-scrollbar-base-color: rgb(0, 0, 0); -ms-scrollbar-face-color: rgb(240, 240, 240); -ms-scrollbar-3dlight-color: rgb(227, 227, 227); -ms-scrollbar-shadow-color: rgb(160, 160, 160); -ms-scrollbar-highlight-color: rgb(255, 255, 255); -ms-scrollbar-darkshadow-color: rgb(105, 105, 105); -ms-scrollbar-arrow-color: rgb(0, 0, 0);”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″>
<meta http-equiv=”X-UA-Compatible” content=”IE=10″>
<meta name=”GENERATOR” content=”MSHTML 11.00.9600.16428″>
<style id=”owaParaStyle” style=”display: none;”><!–P {margin-top:0;margin-bottom:0;}–></style>
</head>
<body tabindex=”0″ style=”” dir=”ltr” aria-label=”Message body” fPStyle=”1″>
<div name=”divtagdefaultwrapper” id=”divtagdefaultwrapper” style=”font-family: Calibri,Arial,Helvetica,sans-serif; font-size: 12pt; color: #000000; margin: 0″>
<p>Hi all,</p>
<p> </p>
<p>This message is used for testing EWS access to user’s mailbox.</p>
<p> </p>
<p>Regards,</p>
<p>Owner Account</p>
<p> </p>
</div>
</body>
</html>

*** Testing user ‘Third.User@ExampleCompany.onmicrosoft.com’ ***

Exception is thrown: The account does not have permission to impersonate the requested user.

*** Testing user ‘Fourth.User@ExampleCompany.onmicrosoft.com’ ***

Exception is thrown: The account does not have permission to impersonate the requested user.

*** Testing user ‘Mail.Admin@ExampleCompany.onmicrosoft.com’ ***

Exception is thrown: The account does not have permission to impersonate the requested user.

************************ Console – End *************************
Из результатов видно, что пользователь Mail Admin получил доступ только к почтовым ящикам пользователей First User и Second User. Кроме того, по умолчанию пользователь не может имперсонифицировать сам себя – доступ к почтовому ящику Mail Admin завершился исключением.


1. Все используемые IP-адреса, имена серверов, компьютеров, доменов, пользователей, являются фиктивными и используются исключительно в демонстрационных целях.
2. Информация приводится «AS IS».

8 thoughts on “Доступ к почтовому ящику имперсонифицированного пользователя в Exchange Online

  1. При выполнении программы возникает ошибка: The request failed. Базовое соединение закрыто: Непредвиденная ошибка при передаче.

    1. В какой строке возникает ошибка?
      Выполнены ли настройки пользователей, описанные в предыдущих статьях?
      Проверяли ли выполнение программы отладчиком, не возникает ли проблем при автоопределении сервиса?
      Может ли проблема возникать из-за особенностей firewall?

      1. Проблема в методе service.AutodiscoverUrl( autodiscoverAddress, RedirectionUrlValidationCallback); Выводит ошибку The Autodiscover service couldn’t be located. Настройки выполнены, firewall отключен.

        1. Похоже на проблему с доступом.

          1. Нужно проверить, что параметры используемой Вами учетной записи (Mail.Admin@ExampleCompany.onmicrosoft.com в моем случае) корректно введены, пароль не просрочен, и под этой учеткой можно зайти на https://login.microsoftonline.com/

          2. Прочитайте следующее обсуждение http://community.office365.com/en-us/forums/158/t/76342.aspx. В частности, проверить подключение к серверу:

          Johnny Zhang MSFT Support
          Post replied on 11/20/2012 7:31 AM

          Hi Nick,

          Autodiscover service in Office 365 just can let user automatically configure their Outlook connect to Exchange online on the Auto Account Setup page of the wizard. We can verify if the service is good through this way. Also we can check it via https://www.testexchangeconnectivity.com/
          In this case, there is no further information about some changes made to Office 365 impact Autodiscover service.

          Thanks,
          Johnny Zhang

          3. Еще одна возможная причина с новыми пользователями, которые должны изменить пароль при первом входе в систему http://stackoverflow.com/questions/19909442/exchange-impersonation-in-service-account-autodiscover-service-couldnt-be-loca:
          The credentials were correct, but it seems that for accounts set to “user has to change password on first login”, access to the autodiscover service is denied. I changed that setting in AD and now it works.

  2. 1 и 3 вариант исключаем, проверили .
    при 2 варианте: Не удается проверить потенциальный URL-адрес автообнаружения https://наш домен/AutoDiscover/AutoDiscover.xml (проверяли по этой ссылке). Скажите пож-та с чем это может быть связано?

    1. Результаты тестирования домена приведены в заметке https://ireznykov.wordpress.com/2014/02/21/testing-autodiscover-office365/. Хотя в целом тест успешен, адрес https://ExampleCompany.onmicrosoft.com/AutoDiscover/AutoDiscover.xml тоже не прошел проверку. Под ним указана ссылка на статью MSDN с описанием [стандартных] настроек DNS.
      Вы используете интеграцию с on-premise AD? Используется ли пользовательский домен? Может, проблемы в настройках DNS Вашего домена?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.