Как аутентифицировать консольное приложение с помощью управляемого API Exchange Online / EWS?

Я разрабатываю консольное приложение для личного использования, которое использует управляемый API веб-служб Exchange в качестве альтернативы Redemption (который я, к сожалению, не могу использовать). Моя конечная цель - использовать приложение в запланированной задаче Windows для подключения к моему почтовому ящику Exchange и выполнять некоторые задачи, такие как создание папок в определенное время в течение года, перемещение писем в эти папки, установка политик хранения для элементов и т. Д.

Приложение идет хорошо, но мне любопытно, как лучше всего реализовать безопасную аутентификацию для приложения, чтобы я мог использовать это на работе. Я знаю Exchange Online не позволит мне подключиться автоматически с учетными данными по умолчанию (не уверен, включает ли это современную проверку подлинности ... см. Ниже), и я придется передать их явно. В процессе разработки я явно передаю свой идентификатор пользователя и пароль в Exchange, используя следующий код:

string userId = UserPrincipal.Current.EmailAddress;
SecureString securePwd = new SecureString();

Console.Write("Current User ID/Email Address: {0}\n", userId);
Console.Write("Enter Password: ");

do
{
    key = Console.ReadKey(true);

    // Ignore the Backspace and Enter keys.
    if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter)
    {
        // Append the character to the password.
        securePwd.AppendChar(key.KeyChar);
        Console.Write("*");
    }
    else
    {
        if (key.Key == ConsoleKey.Backspace & securePwd.Length > 0)
        {
            securePwd.RemoveAt(securePwd.Length - 1);
            Console.Write("\b \b");
        }
        else if (key.Key == ConsoleKey.Enter)
        {
            break;
        }
    }
} while (true);

service.Credentials = new WebCredentials(new NetworkCredential(userId, securePwd));

Я надеялся, так как я буду создавать свою запланированную задачу Windows с выбранной опцией Run whether user is logged on or not и введу свой пароль, чтобы приложение могло использовать и передавать те же учетные данные, что и запланированная задача, поэтому мне не нужно хранить свой пароль вообще, но я пока не нашел ничего, что позволяло бы это делать.

Моя работа включила современную проверку подлинности с помощью Exchange Online и, похоже, передает мои учетные данные Windows в Exchange, когда я использую клиент Outlook, без необходимости явно вводить мои учетные данные для клиента Outlook. Есть ли что-то подобное в управляемом API EWS, которое позволит моему приложению входить в систему с моими учетными данными Windows без их явной передачи? Я знаю, что вы можете зарегистрировать свое приложение и использовать OAuth, но я хотел избежать этого, поскольку это для моего личного использования, и я не уверен, что смогу зарегистрировать свое приложение на работе.

Если это невозможно, я видел несколько статей, например этот, в котором упоминается использование диспетчера учетных данных Windows, и это выглядит многообещающе, но похоже, что мне все еще может потребоваться что-то дополнительное с моим паролем до хранение его. Если я создам учетные данные в диспетчере учетных данных Windows и реализую код по ссылке выше, используя приведенный ниже код (и используя Пакет NuGet CredentialManagement), пароль отображается в виде обычного текста.

private const string PasswordName = "CredentialTest";

public static void Main(string[] args)
{
    LoadCredential();
    Console.ReadKey();
}

public static void LoadCredential()
{
    using (var cred = new CredentialManagement.Credential())
    {
        cred.Target = PasswordName;
        cred.Load();

        Console.WriteLine("Password: {0}", cred.Password);            
    }
}

Рекомендуется ли читать пароль как безопасную строку, зашифровать его с помощью ключа, который хранится в зашифрованном разделе файла app.config, и сохранить зашифрованный пароль в диспетчере учетных данных Windows?

Еще один интересный элемент, с которым я столкнулся, - это класс ClientCertificateCredentials в управляемом API EWS. К сожалению, я не видел примеров его использования. Это альтернативный метод аутентификации? Можно ли использовать самозаверяющий сертификат для этого метода? Если да, требуется ли хранить закрытый ключ на сервере Exchange Online?

Я открыт для других идей и ценю помощь.

Спасибо!


person user2063351    schedule 25.10.2019    source источник


Ответы (1)


Диспетчер учетных данных Windows, конечно же, является опцией (именно так Outlook по-прежнему хранит пароли POP3 / IMAP4 / SMTP и используется для хранения учетных данных Exchange).
Имейте в виду, что Office 365 отключит обычную проверку подлинности в октябре 2020 года.
OAuth может быть вариантом, но это означает, что вам все равно нужно будет каким-то образом запрашивать у пользователя учетные данные и сохранять токены доступа и обновления каким-то образом.
Предпочтительным решением является использование аутентификации на основе сертификатов - см., например, https://developermessaging.azurewebsites.net/2018/09/11/authenticating-against-exchange-web-services-using-certificate-based-oauth2-tokens/
Но для этого требуется импорт сертификата на стороне сервера, что требует прав администратора.

person Dmitry Streblechenko    schedule 27.10.2019
comment
Это несколько не по теме, но как в OutlookSpy вы вызываете EWS, не заставляя пользователя вводить свои учетные данные? Я видел примеры, которые используют XmlHttpRequest в VBA для отправки запросов EWS SOAP, но все примеры явно задают учетные данные. Мне любопытно, потому что вы упомянули, что Microsoft отключит базовую аутентификацию в октябре 2020 года, и я подумал, что, возможно, смогу реализовать альтернативу, используя только VBA или надстройку COM, как вы, если я смогу использовать любую из них. учетные данные вошедшего в систему пользователя. - person user2063351; 08.11.2019
comment
OutlookSpy исправляет функции WinHTTP и перехватывает токены аутентификации. - person Dmitry Streblechenko; 08.11.2019
comment
Я предполагаю, что это не то, что я могу сделать с помощью VBA, верно? - person user2063351; 08.11.2019
comment
Да, вам понадобится C ++ или Delphi. Теоретически вы можете использовать обходные пути в C #, но мне было бы неудобно делать это на управляемом языке. - person Dmitry Streblechenko; 08.11.2019
comment
Итак, вы не можете сделать это только с VBA, и вам придется создать надстройку COM с C ++ / Delphi для перехвата токенов аутентификации, верно? У вас есть справочник о том, как перехватывать токены аутентификации с помощью C ++ / Delphi? - person user2063351; 08.11.2019
comment
Нет ссылки, но по сути вы можете перехватить функции WinHttpAddRequestHeaders / WinHttpSetCredentials / WinHttpSendRequest с помощью Detours. - person Dmitry Streblechenko; 08.11.2019