Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I determine if an MSAL account has an Exchange based email system? (got an exception)

I am working with MSAL and have a user who received the following error:

{  
   "error":{  
      "code":"ResourceNotFound",
      "message":"Resource could not be discovered.",
      "innerError":{  
         "request-id":"99b44a33-e5cd-4b69-9730-32d72e1f4ebf",
         "date":"2016-12-11T03:51:37"
      }
   }
}

The code is the default MSAL demo code:

    public async Task<ActionResult> ReadMail()
    {            
        try
        {
            string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
            ConfidentialClientApplication cca = new ConfidentialClientApplication(clientId, null,
                new ClientCredential(appKey), new MSALSessionCache(signedInUserID, this.HttpContext));                
            string[] scopes = { "Mail.Read" };
            AuthenticationResult result = await cca.AcquireTokenSilentAsync(scopes);

            HttpClient hc = new HttpClient();
            hc.DefaultRequestHeaders.Authorization =
                new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", result.Token);                
            HttpResponseMessage hrm = await hc.GetAsync("https://graph.microsoft.com/v1.0/me/messages");
            string rez = await hrm.Content.ReadAsStringAsync();
            ViewBag.Message = rez;

            return View();
        }
        catch (MsalSilentTokenAcquisitionException)
        {
            ViewBag.Relogin = "true";
            return View();
        }
        catch (Exception eee)
        {
            ViewBag.Error = "An error has occurred. Details: " + eee.Message;
            return View();
        }
    }

It turns out that the integration is like this:

  1. It's a Hybrid Exchange system
  2. Some mailboxes are located on Office 365.
  3. Some mailboxes are located on premise.
  4. Other mailboxes are on a 3rd party mail system (Intermedia) (the directory syncs to AD Connect via a custom script)

Question

How should I defensively code for the above situation? (or similar hybrid situations)?

like image 287
makerofthings7 Avatar asked Dec 11 '16 04:12

makerofthings7


1 Answers

Old question but it seems others have run into this.

This isn't really an MSAL issue since the token itself isn't the problem here. The exception stems from calling https://graph.microsoft.com/v1.0/me/messages when the user doesn't have an accessible mailbox.

You generally can determine which resources have been assigned to a user by looking at that user's provisionedPlans collection:

 https://graph.microsoft.com/v1.0/me?$select=provisionedPlans

This will return a collection resources that have been provisioned for the user. For example, this user does not have Exchange provisioned:

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(provisionedPlans)/$entity",
    "provisionedPlans": [
        {
            "capabilityStatus": "Enabled",
            "provisioningStatus": "Success",
            "service": "SharePoint"
        },
        {
            "capabilityStatus": "Enabled",
            "provisioningStatus": "Success",
            "service": "SharePoint"
        }
    ]
}

Compare this with this user that does have Excange provisioned:

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(provisionedPlans)/$entity",
    "provisionedPlans": [
        {
            "capabilityStatus": "Enabled",
            "provisioningStatus": "Success",
            "service": "MicrosoftOffice"
        },
        {
            "capabilityStatus": "Enabled",
            "provisioningStatus": "Success",
            "service": "exchange"
        },
        {
            "capabilityStatus": "Enabled",
            "provisioningStatus": "Success",
            "service": "MicrosoftCommunicationsOnline"
        },
        {
            "capabilityStatus": "Enabled",
            "provisioningStatus": "Success",
            "service": "SharePoint"
        },
        {
            "capabilityStatus": "Enabled",
            "provisioningStatus": "Success",
            "service": "SharePoint"
        }
    ]
}

A similar property that may also be useful is assignedPlans. This returns the resources that have been assigned to the user and is useful for determining if provisioning simply hasn't occurred yet or for resources that are not formally "provisioned" such as Microsoft Teams.

That said, you should always defensively code for the possibility that a user doesn't have or lacks permission for a resource you're requesting. There are several scenarios where a resource may be inaccessible due to an outage or user permissions and the only sure fire way to handle these scenarios is to backstop with solid exception handling.

like image 128
Marc LaFleur Avatar answered Sep 27 '22 15:09

Marc LaFleur