Skip to content

Instantly share code, notes, and snippets.

@gscales
Created January 14, 2022 00:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gscales/8a8eafc85029ce31f01f0a289469d46d to your computer and use it in GitHub Desktop.
Save gscales/8a8eafc85029ce31f01f0a289469d46d to your computer and use it in GitHub Desktop.
CustomTokenCredentials implmenation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Exchange.WebServices.Data;
using System.Threading.Tasks;
using System.Net;
using System.Security;
using Microsoft.Identity.Client;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json.Linq;
namespace BasicToOAuthImplmentation
{
public class MSALDelegateTokenClass : Microsoft.Exchange.WebServices.Data.Credentials.CustomTokenCredentials
{
private const string GraphScope = "https://graph.microsoft.com/User.Read";
private string ClientId { get; set; }
private string TenantId { get; set; }
private string RedirectUri { get; set; }
private string EWSAuthScope { get; set; } = "https://outlook.office.com/EWS.AccessAsUser.All";
public MSALDelegateTokenClass(string clientId, string tenantid, string redirectUri)
{
ClientId = clientId;
TenantId = tenantid;
RedirectUri = redirectUri;
}
public IPublicClientApplication app { get; set; }
public override string GetCustomToken()
{
if (app == null)
{
PublicClientApplicationBuilder pcaConfig = PublicClientApplicationBuilder.Create(ClientId).WithTenantId(TenantId);
app = pcaConfig.WithRedirectUri(RedirectUri).Build();
}
var accounts = app.GetAccountsAsync().GetAwaiter().GetResult();
AuthenticationResult result = null;
try
{
result = app.AcquireTokenSilent(new[] { EWSAuthScope }, accounts.FirstOrDefault())
.ExecuteAsync().GetAwaiter().GetResult();
}
catch (MsalUiRequiredException ex)
{
// A MsalUiRequiredException happened on AcquireTokenSilent.
// This indicates you need to call AcquireTokenInteractive to acquire a token
try
{
result = app.AcquireTokenInteractive(new[] { EWSAuthScope })
.ExecuteAsync().GetAwaiter().GetResult();
}
catch (MsalException msalex)
{
Console.WriteLine(msalex.Message);
//
}
}
catch (Exception ex)
{
throw;
}
return "Bearer " + result.AccessToken;
}
public string GetUserName()
{
if (app == null)
{
var Token = GetCustomToken();
}
var accounts = app.GetAccountsAsync().GetAwaiter().GetResult();
return accounts.FirstOrDefault().Username;
}
public string GetEmailAddress()
{
if (app == null)
{
var token = GetCustomToken();
}
var accounts = app.GetAccountsAsync().GetAwaiter().GetResult();
var graphToken = app.AcquireTokenSilent(new[] { GraphScope }, accounts.FirstOrDefault())
.ExecuteAsync().GetAwaiter().GetResult();
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", graphToken.AccessToken);
var profileResult = client.GetAsync("https://graph.microsoft.com/v1.0/me?$select=mail").GetAwaiter().GetResult();
dynamic profile = JObject.Parse(profileResult.Content.ReadAsStringAsync().GetAwaiter().GetResult());
return profile.mail;
}
}
public string SetAuthenticationScope(string emailAddress)
{
string autodiscoverv2Endpoint = $"https://outlook.office365.com/autodiscover/autodiscover.json/v1.0/{emailAddress}?Protocol=EWS";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
dynamic adResponse = JObject.Parse(client.GetAsync(autodiscoverv2Endpoint).GetAwaiter().GetResult().Content.ReadAsStringAsync().GetAwaiter().GetResult());
if(adResponse.Url != null)
{
EWSAuthScope = "https://" + new Uri(adResponse.Url.ToString()).Host + "/EWS.AccessAsUser.All";
}
return adResponse.Url;
}
}
}
public class MSALAppTokenClass : Microsoft.Exchange.WebServices.Data.Credentials.CustomTokenCredentials
{
private string ClientId { get; set; }
private string TenantId { get; set; }
private SecureString ClientSecret { get; set; }
private string EWSAuthScope { get; set; } = "https://outlook.office.com/.default";
public MSALAppTokenClass(string clientId, string tenantid, SecureString clientSecret)
{
ClientId = clientId;
TenantId = tenantid;
ClientSecret = clientSecret;
}
public IConfidentialClientApplication app { get; set; }
public override string GetCustomToken()
{
if (app == null)
{
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithClientSecret(new System.Net.NetworkCredential(string.Empty, ClientSecret).Password)
.WithTenantId(TenantId)
.Build();
}
AuthenticationResult result = null;
try
{
result = app.AcquireTokenForClient(new[] { EWSAuthScope }).ExecuteAsync().Result;
}
catch (Exception ex)
{
throw;
}
return "Bearer " + result.AccessToken;
}
public string SetAuthenticationScope(string emailAddress)
{
string autodiscoverv2Endpoint = $"https://outlook.office365.com/autodiscover/autodiscover.json/v1.0/{emailAddress}?Protocol=EWS";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible; AcmeInc/1.0)");
dynamic adResponse = JObject.Parse(client.GetAsync(autodiscoverv2Endpoint).GetAwaiter().GetResult().Content.ReadAsStringAsync().GetAwaiter().GetResult());
if (adResponse.Url != null)
{
EWSAuthScope = "https://" + new Uri(adResponse.Url.ToString()).Host + "/.default";
}
return adResponse.Url;
}
}
}
internal class Program
{
static void Main(string[] args)
{
TestDelegatePermissions();
List<string> mailboxesToAccess = new List<string>{
"user1@domain.com",
"user2@domain.com"
};
TestApplicationPermissions(mailboxesToAccess,new NetworkCredential("", "...").SecurePassword);
}
static void TestDelegatePermissions()
{
MSALDelegateTokenClass delegateCreds = new MSALDelegateTokenClass("9d5d77a6-fe09-473e-8931-958f15f1a96b", "1c3a18bf-da31-4f6c-a404-2c06c9cf5ae4", "msal9d5d77a6-fe09-473e-8931-958f15f1a96b://auth");
var emailAddress = delegateCreds.GetEmailAddress();
var ewsURL = delegateCreds.SetAuthenticationScope(emailAddress);
ExchangeService exchangeService = new ExchangeService();
exchangeService.Credentials = delegateCreds;
// For Autodiscover V1 use
// exchangeService.AutodiscoverUrl(emailAddress, RedirectionUrlValidationCallback);
exchangeService.Url = new Uri(ewsURL);
exchangeService.HttpHeaders.Add("X-AnchorMailbox", emailAddress);
var InboxFolder = Folder.Bind(exchangeService, WellKnownFolderName.Inbox);
Console.WriteLine("Done");
}
static void TestApplicationPermissions(List<String> mailboxesToAccess,SecureString clientSecret)
{
ExchangeService exchangeService = new ExchangeService();
MSALAppTokenClass mSALAppToken = new MSALAppTokenClass("c957131d-b228-494e-b1b8-32b6605fadb9", "1c3a18bf-da31-4f6c-a404-2c06c9cf5ae4", clientSecret);
exchangeService.Credentials = mSALAppToken;
foreach(String mailboxToAccess in mailboxesToAccess)
{
exchangeService.Url = new Uri(mSALAppToken.SetAuthenticationScope(mailboxToAccess));
exchangeService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, mailboxToAccess);
exchangeService.HttpHeaders.Remove("X-AnchorMailbox");
exchangeService.HttpHeaders.Add("X-AnchorMailbox", mailboxToAccess);
var InboxFolder = Folder.Bind(exchangeService, WellKnownFolderName.Inbox);
Console.WriteLine("Mailbox " + mailboxToAccess);
}
Console.WriteLine("Done");
}
private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment