1
votes

I'm developing a console app for personal use that uses the Exchange Web Services Managed API as an alternative to Redemption (which I, unfortunately, cannot use). My ultimate goal is to use the app in a Windows scheduled task to connect to my Exchange mailbox and carry out some tasks like creating folders at specific times during the year, moving emails to those folders, set retention policies on items, etc.

The app is coming along nicely, but I'm curious about how best to implement secure authentication for the app so I can use this at work. I know Exchange Online won't let me connect automatically with default credentials (not sure if this includes Modern Authentication...see below) and I'll have to pass them explicitly. While in development, I'm explicitly passing my user ID and password to Exchange using the following code:

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));

I was hoping, since I will be creating my Windows scheduled task with the Run whether user is logged on or not option selected and will enter my password, that the app could use and pass the same credentials that the scheduled task is using so I don't have to store my password at all, but I haven't found anything that would allow this yet.

My work has enabled Modern Authentication with Exchange Online and that appears to pass my Windows credentials to Exchange when I'm using the Outlook client without requiring me to explicitly enter my credentials for the Outlook client. Is there something similar in EWS Managed API that will allow my app to login with my Windows credentials without explicitly passing them? I know you can register your app and use OAuth, but I wanted to avoid that since this is for my personal use and I'm not sure I'll be able to register my app at work.

If the above isn't possible, I have seen a number of articles, like this one, that mention using the Windows Credential Manager and that looks promising, but it appears as though I may still need to do something additional with my password prior to storing it. If I create a credential in Windows Credential Manager and implement the code at the link above using the code below (and using the CredentialManagement NuGet package), the password is displayed in plain text.

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);            
    }
}

Is it recommended to read in the password as a secure string, encrypt it using a key that is stored in an encrypted section of the app.config file, and store the encrypted password in Windows Credential Manager?

Another interesting item I came across was the ClientCertificateCredentials class in the EWS Managed API. Unfortunately, I haven't seen any examples of it in use. Is this an alternate method of authentication? Can a self-signed certificate be used for this method? If so, does it require storing a private key on the Exchange Online server?

I'm open to other ideas and appreciate the help.

Thanks!

1

1 Answers

1
votes

Windows Credentials Manager is of course an option (that is how Outlook still stores POP3/IMAP4/SMTP passwords and used to store Exchange credentials).
Keep in mind that Office 365 will turn Basic authentication off in October 2020.
OAuth might be an option, but that means you'd still need to somehow prompt the user for the credentials and store the access and refresh tokens somehow.
The preferred solution is to use certificate based authentication - see for example https://developermessaging.azurewebsites.net/2018/09/11/authenticating-against-exchange-web-services-using-certificate-based-oauth2-tokens/
But that requires importing certificate on the server side, which requires admin privileges.