Introduction
With Microsoft deprecating Basic Authentication in Exchange Online, you are unable to continue using the Exchange Web Service (EWS) Email Server Profile in On-Premise CRM because it still uses Basic Authentication. Microsoft does provides an Exchange Hybrid Connector solution as a bridge between On-Premise CRM and Exchange Online however, for highly security sensitive organizations, the elevated permissions can be deemed too high risk. The Hybrid Connector needs to be configured by someone with the Exchange Global Admin role and the Connector continues to execute under the context of the global admin. Once configured as an Email Server Profile in CRM, a CRM System Admin is allowed to add any user from Azure Active Directory (AAD) and begin syncing their Exchange mailbox with CRM. There are certain scenarios where a user may want to grant another user permission to access their mailbox, but due to the execution context of the Hybrid Connector, it’s facilitating the ability to sync the user’s mailbox with CRM without the end user’s consent. Previously, with EWS we had only been able to sync mailboxes for accounts that we had the username/password for, thus preventing CRM Admins from accessing the mailbox of just any AAD user. In an ordinary business scenario, the Hybrid Connector’s elevated AAD permission may not be a cause for concern. However, in institutions like higher education, their AAD contains student, faculty and staff members across UW including UW Medicine. So, the Hybrid Connector elevated execution permission raises numerous privacy concerns including both HIPPA and FERPA compliance issues.
Due to these concerns, we worked with Microsoft to come up with an innovative solution utilizing Azure API Management. This API serves as a middle-man between CRM and Exchange Online by intercepting the Basic Authentication requests from CRM and translating them into an Azure App Registration-based OAUTH authentication that Exchange Online will accept. This allows On-Premise CRM to continue operating as it always with Basic Authentication while interfacing with other MS services in a more modern OAUTH based approach.
High Level Architecture
The following diagram details the components involved in the solution.
Configuration
AAD
- Login with the user who has Exchange admin role in Exchange Online and preferably Dynamics Admin role in CRM OnPrem organization.
- Azure portal -> Azure Active Directory -> App Registrations -> New Registration
- Create a 3rd party app registration following https://learn.microsoft.com/en-us/power-platform/admin/connect-exchange-online-server-profile-oauth#register-your-app
- Make sure to grant Admin consent when Exchange Online Permissions are added to the app
- Make sure to note APP ID and client secret.
- This app will be the one APIM will use to interact with Exchange Online.
- <appId1, secret1> will be available to authenticate as this app after this configuration.
Exchange online
Configure an Application Access Policy for the above 3rd party app registration to restrict access to the 6 mailboxes. https://learn.microsoft.com/en-us/graph/auth-limit-mailbox-access
This step will need to be completed by an Exchange Admin. Any mailboxes that are going to be use this server profile need to be added to this access policy. We opted to use a service account for security purposes and this service account also needed to be added to the Access Policy.
Creating APIM
- Create or go to an existing Azure subscription in the Azure portal.
- Create a new Azure Resource Group in the above subscription if needed.
- Go to the resource group where you want to create the APIM end point.
- Click on “Create” and search for apimanagement and click “Create” -> “API Managment” to create API Management resource
- Provide appropriate details and select desired pricing tier. After reviewing the pricing tier information, we determined that the Basic tier was sufficient for our needs at this time.
- On the Monitoring tab, we elected to use App Insights to track the usage information about the API. You will need to select an existing App Insights resource. If you don’t already have one, you will need to create it before starting the APIM setup.
- This isn’t a requirement, but we elected to enable this so that we could easily track the usage information. We had questions about how much traffic was going to be coming through on the API.
- On the Scale tab, we elected to just use 2.
- Keep defaults on “Managed identity” and “Virtual network”
- Select all protocols in “Protocol” Section
- Add “Tags” if needed.
- Click create on “Review and Install” section after going through all the settings.
- Wait for 10-15 minutes for the APIM resource to be deployed.
- When APIM resource status shows online, click on API section in left hand side pane.
Configuring APIM
- Click “Add API”, select HTTP, and then add EWS (https://outlook.office365.com) end point to the settings. We used “UWEwsApim” for the name and suffix fields.
- “API Url Suffix” is for APIM end point (full url is “Base Url” seen in the screenshot) exposed for inbound request. In our case, the BaseURL is what we ultimately use for our Email Server Profile in Dynamics so make sure to write this URL for later.
- Add “Post operation” for above created API with url “/EWS/Exchange.asmx”
- Open APIM policy editor by clicking the new POST operation, then go to the Backend section and click the “</>” to the right of Policies
- Replace the policy xml with below xml
- Replace the “clientId” value in line 4 above with the Application (client) Id from the AAD App
- Replace the “clientSecret” value in line 5 above with the client secret from the AAD App
- Replace the “tenantId” value in line 6 above with the Tenant Id of AAD
- For the expectedAuthHeader, you will need to take the user name and password you are planning to use with APIM and get the base64 encoded string it in the format “emailaddress:password”. There are various conversion tools you can find on the web to convert text to base64.
- In the “expectedAuthHeader” value in line 7 above, put the base64 value from above after “Basic “. It should look like value=”Basic 123412……”.
- Uncheck “Subscription Required” flag in APIM settings:
<policies>
<inbound>
<base />
<set-variable name="clientId" value="app Id" />
<set-variable name="clientSecret" value="secret Value" />
<set-variable name="tenantId" value="aad directory Id" />
<set-variable name="expectedAuthHeader" value="Basic YWJjQGZvby5jb206cGFzc3dvcmQ=" />
<choose>
<when condition="@(context.Request.Headers.GetValueOrDefault("Authorization", "") != context.Variables.GetValueOrDefault<string>("expectedAuthHeader"))">
<return-response>
<set-status code="401" reason="Unauthorized" />
<set-header name="WWW-Authenticate" exists-action="override">
<value>Basic realm="Your-Realm-Name"</value>
</set-header>
<set-body>Not a valid user.</set-body>
</return-response>
</when>
</choose>
<send-request mode="new" response-variable-name="bearerToken" timeout="20" ignore-error="false">
<set-url>@($"https://login.microsoftonline.com/{context.Variables.GetValueOrDefault<string>("tenantId")}/oauth2/v2.0/token")</set-url>
<set-method>POST</set-method>
<set-header name="Content-Type" exists-action="override">
<value>application/x-www-form-urlencoded</value>
</set-header>
<set-body>@($"grant_type=client_credentials&scope=https://outlook.office.com/.default&client_id={context.Variables.GetValueOrDefault<string>("clientId")}&client_secret={context.Variables.GetValueOrDefault<string>("clientSecret")}")</set-body>
</send-request>
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + (String)((IResponse)context.Variables["bearerToken"]).Body.As<JObject>()["access_token"])</value>
</set-header>
<set-header name="Ocp-Apim-Subscription-Key" exists-action="delete" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Dynamics (on-premises)
- Create Exchange (on-premises) Email Server Profile
- Specify to not use AutoDiscovery as we want to point Dynamics directly to APIM basic auth endpoint here.
- Specify EWS endpoint defined in Step 2 & 3 of the APIM configuration section
- In the Credential section, select Credentials Specified on Email Server Profile and then enter the service account credentials matching those defined in Step 9 of the APIM configuration section.
- Associate a test mailbox to the email server profile and disable “Allow to Use Credentials for Email Processing” on the individual mailboxes.
- Approve the mailbox.
- Test & enable the mailbox.
- If everything is working, you should see “Success” in the Incoming/Outgoing Email Status boxes on the mailboxes.
- If not, you will see Failure in the Incoming/Outgoing Email Status boxes in the Mailbox. Check the “Alerts” section on the left of the mailbox for error messages and consult the next section.
Potential Errors
- 401 Unauthorized
- On our first few tests, I was getting a 401 Unauthorized error. Turns out that I had put the client secret Id into the clientId field of the policy configuration when it is supposed to be the clientId of the AAD App.
- 403 Forbidden
- After getting past the 401 error, I started getting the 403 error. Ultimately, this was due to our service account not being added into the Access Policy list so it wasn’t able to access Exchange through the AAD App.
- You will also received this error if you try to Test&Enable a mailbox that hadn’t been added to the Access Policy list. In my case, only a small subset of our mailboxes are configured to use this Server Profile and I inadvertently attempted to selected a mailbox not on the list.
- For any other errors, you will likely need to collect a trace. This can be done by installing Fiddler onto the CRM Async Server which handles processing the email messages.
Account Configuration
Adding New Accounts
Any accounts that need to use Server-Side Sync must be added to the Application Access Policy created in the Exchange Configuration section above. This is required so that the service account can access their mailbox through the API.
Once that is complete, you can proceed with adding the Email Server Profile to the mailbox in CRM.
- Open the appropriate mailbox record (If a new CRM user, create the user in CRM first)
- Select the correct Email Server Profile.
- Approve the mailbox.
- Test & enable the mailbox.
- If everything is working, you should see “Success” in the Incoming/Outgoing Email Status boxes on the mailboxes.
- If not, you will see Failure in the Incoming/Outgoing Email Status boxes in the Mailbox. Check the “Alerts” section on the left of the mailbox for error messages and consult the next section.
Comments are closed