Closed AdhocAdam closed 4 years ago
To be refined -
Register an App in Azure Active Directory Set the Redirect URI to "Public client/native (mobile & desktop). Set the value to "urn:ietf:wg:oauth:2.0.oob"
Take note of the Application (client) ID and Directory (Tenant) ID
(optional) Set the logo to distinguish your application within your tenant. This makes it easy to distinguish the app if you registered other applications within your Azure tenant. You can use the following 215x215 png.
Choose the APIs the app can leverage.
Scroll to the bottom of available APIs. Choose Exchange, then choose "Delegated Permissions", finally search for "EWS.AccessAsUser.All" and finally "Add permissions"
#this is the application/client id for the registered Azure Application
$clientId = ""
#this is your full Azure Tenant Name. For example, mydomain.onmicrosoft.com.
#Unsure? Get it from the Overview blade in the Azure portal https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Overview
$tenant = ""
$resource = "https://graph.microsoft.com/";
#build and make the request. Show the auth Code in the shell to enter on Microsoft's site.
$requestBody = @{
client_id = $clientId
resource = $resource
}
$response = Invoke-RestMethod -Method "POST" -Uri "https://login.microsoftonline.com/$tenant/oauth2/devicecode" -Body $requestBody
Write-Output $response.message
At this point, the workflow account has consented to the application. How do you know this worked? As the workflow account, head over to https://account.activedirectory.windowsazure.com/r#/applications. Here you should see the configured application in the list of applications. It's possible that it may take a few minutes before it appears.
Assuming EWS is used. Per the Microsoft documentation Authenticate an EWS application by using OAuth and then translating the C# into PowerShell that is mocked up into the connector:
$tenantName = "" #this is your Azure Tenant Name e.g. mydomain.onmicrosoft.com
$clientId = "" #this is the application/client id of the Azure Active Directory app from above
$clientSecret = "" #this is the application secret generated above
$username = "" #the workflow account's username
$password = "" #the workflow account's password
$tokenReqBody = @{
Grant_Type = "Password"
Client_Id = $clientID
Client_Secret = $clientSecret
Username = $username
Password = $password
Scope = "https://outlook.office.com/EWS.AccessAsUser.All"
}
$tokenReqResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method "POST" -Body $tokenReqBody
#define Exchange assembly and connect to Office 365 EWS
$exchangeEWSAPIPath = "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"
$exchangeEndpoint = "https://outlook.office365.com/EWS/Exchange.asmx"
[void] [Reflection.Assembly]::LoadFile("$exchangeEWSAPIPath")
$exchangeService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
$exchangeService.Url = [System.Uri]$ExchangeEndpoint
$exchangeService.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]($tokenReqResponse.access_token)
#define search parameters, search on the defined classes and get messages that are older than the current time
$inboxFolderName = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox
$inboxFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeService,$inboxFolderName)
$itemView = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ItemView -ArgumentList 1000
$propertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$propertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text
$mimeContentSchema = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.ItemSchema]::MimeContent)
$dateTimeItem = [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived
$now = get-date
$searchFilter = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThanOrEqualTo -ArgumentList $dateTimeItem,$now
#load the items in the Inbox using the the $searchFilter from above, in this case - load ANY kind of message (calendar, encrypted, regular email, OOO, etc.)
$inbox = $exchangeService.FindItems($inboxFolder.Id,$searchFilter,$itemView)
At this point the user is authenticated and is able to process the inbox through Exchange Web Services in Office 365 using OAuth tokens.
Note: If this were to be inserted into one's environment right now with EWS v2.x it should work as expected pending the user consent step.
Assuming the Microsoft Graph API is used. The mail is retrieved through an Invoke-RestMethod call to the Graph.
$tenantName = "" #this is your Azure Tenant Name e.g. mydomain.onmicrosoft.com
$clientId = "" #this is the application/client id of the Azure Active Directory app from above
$clientSecret = "" #this is the application secret generated above
$username = "" #the workflow account's username
$password = "" #the workflow account's password
$tokenReqBody = @{
Grant_Type = "Password"
Client_Id = $clientID
Client_Secret = $clientSecret
Username = $username
Password = $password
Scope = "https://graph.microsoft.com/Mail.Read"
}
#get the token to use with the Graph
$tokenReqResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method "POST" -Body $tokenReqBody
### make a call and ask for the Message Class (e.g. IPM.Note) property since it isn't included in default call: ($filter = Id eq String 0x001a)
$apiUrl = "https://graph.microsoft.com/v1.0/me/mailFolders/Inbox/messages/?`$expand=SingleValueExtendedProperties(`$filter=(Id%20eq%20'String%200x001a'))"
$data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($tokenReqResponse.access_token)"} -Uri $apiUrl -Method "GET"
$inbox = $data.value | select from, toRecipients, ccRecipients, subject, sentDateTime, receivedDateTime, id, conversationid, hasattachments, @{Name = 'ItemClass'; Expression = {$_.singleValueExtendedProperties | select value -ExpandProperty value }}
At this point the user is authenticated and is able to process the inbox through the Microsoft Graph in Office 365 using OAuth tokens.
Note: If this were to be inserted into one's environment right now, it will not work as expected as things like signed/encrypted messaging are not accounted for. Other properties core to the basic IPM.Note (email) class require light refactoring as some property names have changed.
The recent release of Exchange Connector 4.0 has now introduced OAuth support for Exchange Online. In an effort to continue to maintain a low barrier to entry to this connector as well as continued support for those currently using it in 365. A similar authentication method will be followed wherein:
Wiki being updated with more streamlined documentation on configuration over here.
OAuth functionality to be available with #206
The location of EWS has moved within the Azure Portal.
UPDATE: Basic Authentication to be disabled in second half of 2021 for those actively using it.
With the upcoming deprecation of Basic Authentication to Office 365 through Exchange Web Services API on October 13th, 2020. It's a priority for those running their Service Manager inbox in 365 that the connector continues to work.This request sees to enable the connector to handle on-premise and hosted Exchange environments by introducing support for OAuth2 tokens as a means to authenticate to Exchange.
High level steps include: