0
votes

I am trying to use a HttpClient to connect to a web service hosted in an Azure App Service that is secured with AAD using Managed Service Identity. When trying to connect from client code using a AzureServiceTokenProvider I'm getting a AzureServiceTokenProviderException when trying to get a token

Base setup:

AAD tenant AADX.onmicrosoft.com Contains an Application Registration for the target app service mytest. It has Application ID XXXXXXXX-XXXX-49e6-a806-5440b00282b1 and according to the manifest it has identifier URL "https://AADX.onmicrosoft.com/mytest"

An App service "mytest" has been created in a subscription under this AAD so with URL https://mytest.azurewebsites.net

In authentication setting for the app service "App Service Authentication" is on. Action to take when request is not authenticated is set to "Log in with Azure Active Directory". AAD authentication provider is configured with express settings, pointing to AADX and using the "mytest" application.

We have resources that need to talk to this App service both inside our azure tenant and outside it. The resources outside the azure tenant route through API management to the specific parts of the API they need, using Subscription keys in a controlled manner.

There are app services, and desktop apps hosted in RemoteApp that need to access the full service hosted under the app. Managed identity is switched on for all infrastructure within the tenant that needs to connect.

When I use the code below I get an exception regarding the failure to get a token. If I change the requested resource to "https://login.microsoftonline.com/" then I can get a token, though not a correct one (it actually picks up my MS online login not the account selected in options)

        private static HttpClient ConnectToClient()
        {
            String BaseUrl = "https://mytest.azurewebsites.net/";
            String AdResource = "https://AADX.onmicrosoft.com/mytest";

            AzureServiceTokenProvider TokenProvider = new AzureServiceTokenProvider();
            String Token = TokenProvider.GetAccessTokenAsync(AdResource).Result;

            HttpClient Client = new HttpClient()
            {
                BaseAddress = new Uri(BaseUrl)
            };

            Client.DefaultRequestHeaders.Accept.Clear();
            Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));


            Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token);

            return Client;
        }

        private static String GetContent()
        {
            String Output = String.Empty;

            using (HttpClient Client = ConnectToClient())
            {
                HttpResponseMessage ResponseMessage = Client.GetAsync("api/Test/").Result;

                if (ResponseMessage.IsSuccessStatusCode)
                {
                    Output = ResponseMessage.Content.ReadAsStringAsync().Result;
                }
            }

            return Output;
        }

I would expect Token to be returned as a valid value to be used as a bearer token. Instead at the point GetAccessTokenAsync is called the following exception is thrown:

System.AggregateException HResult=0x80131500 Message=One or more errors occurred. (Parameters: Connection String: [No connection string specified], Resource: https://AADX.onmicrosoft.com/mytest, Authority: . Exception Message: Tried the following 3 methods to get an access token, but none of them worked.

Parameters: Connection String: [No connection string specified], Resource: https://AADX.onmicrosoft.com/mytest, Authority: . Exception Message: Tried to get token using Managed Service Identity. Unable to connect to the Managed Service Identity (MSI) endpoint. Please check that you are running on an Azure resource that has MSI setup. Parameters: Connection String: [No connection string specified], Resource: https://AADX.onmicrosoft.com/mytest, Authority: . Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Exception for Visual Studio token provider Microsoft.Asal.TokenService.exe : TS003: Error, TS004: Unable to get access token. 'Failed to refresh access token'

2
A managed identity set up for an App Service helps code running in that App Service connect to other Azure resources. That managed identity is irrelevant to clients running elsewhere trying to connect to that App Service. If you want to use a managed identity to acquire a token, the code that's trying to get the token needs to be running in Azure on a resource with managed identity enabled (an App Service or a VM).nlawalker

2 Answers

0
votes

AzureServiceTokenProvider uses Managed Identity when deployed on Azure. When not on Azure, it does support other authentication options. You can use an explicit service principal credential specified in an environment variable without a code change. Please see the documentation here.

0
votes

Every Visual Studio version provides own version of Microsoft.Asal.TokenService.exe and reflects this in %LOCALAPPDATA%.IdentityService\AzureServiceAuth\tokenprovider.json configuration file. Please validate the extension folder in "Path" there.

For example, for Visual Studio version 16.4 the extension is located in folder "ys2aolp3.2rs":

{ 
  "TokenProviders": [
    { 
      "Path": "c:\\program files (x86)\\microsoft visual studio\\2019\\enterprise\\common7\\ide\\extensions\\ys2aolp3.2rs\\TokenService\\Microsoft.Asal.TokenService.exe",
      "Arguments": [
        "--serviceHubConfig", 
        "\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\Common7\\servicehub.config.json\""
      ], 
      "Preference": 0
    }
  ]
}