Azure / azure-sdk-for-js

This repository is for active development of the Azure SDK for JavaScript (NodeJS & Browser). For consumers of the SDK we recommend visiting our public developer docs at https://docs.microsoft.com/javascript/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-js.
MIT License
2.08k stars 1.2k forks source link

DefaultAzureCredential failed to retrieve a token from the included credentials #15461

Closed Crafoord closed 3 years ago

Crafoord commented 3 years ago

Describe the bug I'm trying to retrieve credentials from my vscode extension. I'm logged in and can see all my subscriptions.

In the README documentation it says that It should be enough to just be logged in, in docs online it's unclear if I actually need to provide environment variables for it to work.

I run the following code:

const credentials = new DefaultAzureCredential()
console.log(credentials)

And it returns:

{
   "UnavailableMessage": "DefaultAzureCredential => failed to retrieve a token from the included credentials",
   "_sources": [
     {},
     {
       "isEndpointUnavailable": null,
       "identityClient": {
         "_withCredentials": false,
         "_httpClient": {
           "proxyAgents": {},
           "keepAliveAgents": {},
           "cookieJar": {
             "version": "tough-cookie@4.0.0",
             "storeType": "MemoryCookieStore",
             "rejectPublicSuffixes": false,
             "cookies": []
           }
         },
         "_requestPolicyOptions": {},
         "_requestPolicyFactories": [
           {},
           {},
           {},
           {},
           {},
           {},
           {},
           {},
           {},
           {},
           {}
         ],
         "authorityHost": "https://login.microsoftonline.com",
         "baseUri": "https://login.microsoftonline.com"
       }
     },
     {},
     {
       "cloudName": "AzureCloud",
       "identityClient": {
         "_withCredentials": false,
         "_httpClient": {
           "proxyAgents": {},
           "keepAliveAgents": {},
           "cookieJar": {
             "version": "tough-cookie@4.0.0",
             "storeType": "MemoryCookieStore",
             "rejectPublicSuffixes": false,
             "cookies": []
           }
         },
         "_requestPolicyOptions": {},
         "_requestPolicyFactories": [
           {},
           {},
           {},
           {},
           {},
           {},
           {},
           {},
           {},
           {},
           {}
         ],
         "authorityHost": "https://login.microsoftonline.com",
         "baseUri": "https://login.microsoftonline.com"
       },
       "tenantId": "common"
     }
   ]
 }

To Reproduce Steps to reproduce the behavior:

  1. Login on Azure Account extension
  2. Install @azure/identity@1.3.0
  3. Login to your azure account
  4. new DefaultAzureCredential()

Expected behavior I expect to receive a credential since I'm logged into the extension.

Screenshots Just "Proof" that I'm logged into the extension: image

Additional context I'm also logged into the CLI. I have access to several subscriptions. I have not configured ANY environment variables (not needed?)

When running VisualStudioCodeCredential() directly I get this back:

{
   "cloudName": "AzureCloud",
   "identityClient": {
     "_withCredentials": false,
     "_httpClient": {
       "proxyAgents": {},
       "keepAliveAgents": {},
       "cookieJar": {
         "version": "tough-cookie@4.0.0",
         "storeType": "MemoryCookieStore",
         "rejectPublicSuffixes": false,
         "cookies": []
       }
     },
     "_requestPolicyOptions": {},
     "_requestPolicyFactories": [
       {},
       {},
       {},
       {},
       {},
       {},
       {},
       {},
       {},
       {},
       {}
     ],
     "authorityHost": "https://login.microsoftonline.com",
     "baseUri": "https://login.microsoftonline.com"
   },
   "tenantId": "common"
 }
sadasant commented 3 years ago

@Crafoord, hello, I’m Daniel! I’ll be doing my best to help you.

Before I give you a more concrete answer, please help me by answering the following questions:

With that information, please give us about a day more for us to prepare a good response for you.

Crafoord commented 3 years ago

@Crafoord, hello, I’m Daniel! I’ll be doing my best to help you.

Before I give you a more concrete answer, please help me by answering the following questions:

  • It wasn’t clear for me, does VisualStudioCodeCredential work for you if you use it directly?
  • What version of Visual Studio Code are you using?

With that information, please give us about a day more for us to prepare a good response for you.

Thanks @sadasant !

VSC version:

Version: 1.56.2
Commit: 054a9295330880ed74ceaedda236253b4f39a335
Date: 2021-05-12T17:44:30.902Z (2 wks ago)
Electron: 12.0.4
Chrome: 89.0.4389.114
Node.js: 14.16.0
V8: 8.9.255.24-electron.0
OS: Darwin x64 20.2.0

Regarding the VisualStudioCodeCredential it looks like it's getting a credential back but when trying to get an app-config/key vault secret I get this error:

      RestError
          at new RestError (/Users/xxxxxx/dev/xxxxxx/server/node_modules/@azure/core-http/dist/index.js:2362:28)
          at handleErrorResponse (/Users/xxxxxx/dev/xxxxxx/server/node_modules/@azure/core-http/dist/index.js:3246:17)
          at /Users/xxxxxx/dev/xxxxxx/server/node_modules/@azure/core-http/dist/index.js:3182:18
          at processTicksAndRejections (node:internal/process/task_queues:93:5)
        name: "RestError"
        statusCode: 403

Also the "credential" I'm getting back:

VisualStudioCodeCredential {
  cloudName: 'AzureCloud',
  identityClient: IdentityClient {
    _withCredentials: false,
    _httpClient: NodeFetchHttpClient {
      proxyAgents: {},
      keepAliveAgents: {},
      cookieJar: [CookieJar]
    },
    _requestPolicyOptions: RequestPolicyOptions { _logger: undefined },
    _requestPolicyFactories: [
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object]
    ],
    authorityHost: 'https://login.microsoftonline.com',
    baseUri: 'https://login.microsoftonline.com'
  },
  tenantId: 'common'
}

I only got it working if I put in the environment variables for an SPM.

sadasant commented 3 years ago

@Crafoord Hello! I have an update.

Keep in mind that we will use this issue later to improve our documentation. In the mean time, my focus will be to make sure that you’re able to get the VisualStudioCodeCredential to work.

I’m sorry if these steps are obvious. Please make sure to follow them. Please let us know if anything unexpected happens.

Steps:

  1. Make sure to have the Azure Account extension installed on your VSCode.
  2. Make sure to sign in to your Azure Account through the VSCode extension (for example, with CMD+Shift+P, then Azure: Sign In).
  3. Go to your Azure account on the Azure portal.
  4. Go to Active Directory through the portal.
  5. Create an App Registration (Enterprise app). If you already have an App Registration, you can use that one.
  6. Go to the App Registration on the Azure portal’s Active Directory. Go to the “Authentication” section of your App Registration. Ensure that the App Registration only has “Mobile and desktop applications” with three values (these should have been assigned by default, as part of any newly created application). This step shouldn’t be necessary, but it will help us simplify the problem if anything unexpected happens.
  7. Go to the “Overview” page of your App Registration, copy the Directory (tenant) ID.
  8. Open the settings of the Azure Account plugin on VSCode, look for the input labeled Azure: Tenant. Paste the Directory (tenant) ID of your App Registration in the input. Click away, effectively giving a bit of time for VSCode to update this setting on the underlying JSON file.
  9. Open a project where you have @azure/identity 1.3.0 installed. Or create a new folder, then run npm init, then npm install --save @azure/identity.
  10. Open the VSCode terminal in the folder of that project. In this folder there should be a node_modules folder present.
  11. Run node.
  12. In Node, enter:
    • var identity = require(“@azure/identity”)
    • var credential = new identity.VisualStudioCodeCredential()
    • credential.getToken(“https://graph.microsoft.com/.default”).then(console.log).catch(console.log)
  13. Your OSX’s Keychain should pop up a window asking for your password to allow node to access the information stored in VS Code Azure. Enter your password, click Allow.
  14. A second prompt will appear from your Keychain asking you for the same password (We know of this issue and we’re working on a solution, let’s try to make this work first, I’ll make sure to follow up with detailed improvements).
  15. After you’ve allowed node to authenticate twice, an object with the structure { token: ‘XYZXYZ’, expiresOnTimestamp: 123123123 } should appear in the terminal of your VSCode. That token means the authentication has succeeded.

Please let me know if this works.

If this works, I know I have to:

If this doesn’t work, once you let us know, please give us about a day to follow up with our next response.

Crafoord commented 3 years ago

Thanks @sadasant

Before I did not get the popup (maybe because I did not do the getToken call?). I did everything in your steps and got popup+token I removed the tenant (step 5-8) and got popup+token I replaced VisualStudioCodeCredential with DefaultAzureCredential and got a popup+token

But when I try to use my credential with app-config like below (I actually get the popup now):

credential = new VisualStudioCodeCredential()
const configClient = new AppConfigurationClient(appConfigUrl, credential)
configClient.getConfigurationSetting({ key: 'SOME_KEY' }).then(console.log).catch(console.log)

I get this back, not very helpful, when logged into the portal I have the Contributor + Owner role for this resource (app config):

RestError:
 {
  "name": "RestError",
  "statusCode": 403,
  "request": {
    "streamResponseStatusCodes": {},
    "url": "https://xxxxxxxxxx.azconfig.io/kv/HTTP_BASE_URL?api-version=1.0",
    "method": "GET",
    "headers": {
      "_headersMap": {
        "accept": "application/vnd.microsoft.appconfig.kv+json, application/json, application/problem+json",
        "user-agent": "azsdk-js-app-configuration/1.1.1 core-http/1.2.4 Node/v15.5.1 OS/(x64-Darwin-20.2.0)",
        "x-ms-client-request-id": "my-request-id",
        "authorization": "REDACTED",
        "cookie": "REDACTED"
      }
    },
    "withCredentials": false,
    "timeout": 0,
    "requestId": "my-request-id"
  },
  "details": {},
  "message": ""
}

Also, just so I can understand, creating the app registration was just for debugging purposes? It kind of eliminates the simplicity of using the VisualStudioCodeCredential if you need to setup and manage a registration IMO.

I realise now that the UnavailableMessage I thought was a problem is a just a class property: * The message to use when the chained token fails to get a token

So when logging credentials after creation will always show :

UnavailableMessage: "DefaultAzureCredential => failed to retrieve a token from the included credentials";
sadasant commented 3 years ago

@Crafoord thank you for your detailed response!

Give us some time to come up with a good response. Thank you for your patience!

sadasant commented 3 years ago

@Crafoord Hello hello,

I’ve tried creating an App Configuration instance to replicate the scenario you’ve shared. I’ve only been able to get a 403 after applying the permissions to my user while the permissions get propagated (after that, things worked well). So, right after you’ve added a user as an owner (though App Configuration Data Owner should be sufficient), the permissions may take some time to be effective.

There are some action items that you could do to help us debug this further:

  1. Let’s try again! I wonder if it would work now that some time has passed.
  2. Let’s try giving your user App Configuration Data Owner permissions besides “Owner.” Also, please try several times over an hour, just in case. (This might not be it, but while the issue is undetermined, I wonder if it helps).
  3. Debug your token to ensure the information matches your user. For that, I’ll write something below.

To debug the token:

Right after you instantiate your credential, please add some code similar to the following:

const getTokenResult = await credential.getToken("https://graph.microsoft.com/.default");
console.log({ getTokenResult });

Inside of getTokenResult there should be a token property with a long value. Copy that value and paste it in https://jwt.ms or https://jwt.io (these sites are safe). Do not paste it here! - go through your token properties and investigate if the values of the following properties make sense to you: For example, the upn property should include your email, the one related to the account you’re using to authenticate, which should be the one that has ownership permissions over your App Registration.

If the values of the token make sense, this means that the token should be valid.

Generally speaking, 403s mean that the user does not have permission to see the resource, so it seems to us that this is about ensuring the right account has the right permissions. It could be something else, of course. We’ll continue investigating after your response.

Crafoord commented 3 years ago

Thanks for the new directives @sadasant,

There are some action items that you could do to help us debug this further:

  1. Let’s try again! I wonder if it would work now that some time has passed.
  2. Let’s try giving your user App Configuration Data Owner permissions besides “Owner.” Also, please try several times over an hour, just in case. (This might not be it, but while the issue is undetermined, I wonder if it helps).
  3. Debug your token to ensure the information matches your user. For that, I’ll write something below.
  1. Did not work 👎
  2. Did work! 👍
  3. My token looks good 👍

More information about .2: It also worked if I gave myself the "Owner" permission. To be clear, I'm part of a group that has Owner, maybe that's not really working out in this case? Something for you to investigate?

My testing flow (I waited 5-10 minutes between each test after changing role assignments):

  1. Be "Owner" through ad group -> does not work 👎
  2. Be "App Configuration Data Owner" directly on my user -> works 👍
  3. Be "Owner" directly on my user -> works 👍
  4. Be "Owner" through ad group -> does not work 👎

Regards

sadasant commented 3 years ago

@Crafoord Thank you for answering back!

This seems to be a service-level bug, since the group permissions should be honored. I’ll route this issue to the service team today.

ghost commented 3 years ago

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @shenmuxiaosen, @avanigupta.

Issue Details
- **Package Name**: @azure/identity - **Package Version**: 1.3.0 - **Operating system**: macOS Big Sur 11.1 - [x] **nodejs** - **version**: 14.16.0 - [ ] **browser** - **name/version**: - [ ] **typescript** - **version**: - Is the bug related to **documentation** in - [x] README.md - [ ] source code documentation - [x] SDK API docs on https://docs.microsoft.com **Describe the bug** I'm trying to retrieve credentials from my vscode extension. I'm logged in and can see all my subscriptions. In the README documentation it says that It should be enough to just be logged in, in docs online it's unclear if I actually need to provide environment variables for it to work. I run the following code: ```js const credentials = new DefaultAzureCredential() console.log(credentials) ``` And it returns: ```js { "UnavailableMessage": "DefaultAzureCredential => failed to retrieve a token from the included credentials", "_sources": [ {}, { "isEndpointUnavailable": null, "identityClient": { "_withCredentials": false, "_httpClient": { "proxyAgents": {}, "keepAliveAgents": {}, "cookieJar": { "version": "tough-cookie@4.0.0", "storeType": "MemoryCookieStore", "rejectPublicSuffixes": false, "cookies": [] } }, "_requestPolicyOptions": {}, "_requestPolicyFactories": [ {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ], "authorityHost": "https://login.microsoftonline.com", "baseUri": "https://login.microsoftonline.com" } }, {}, { "cloudName": "AzureCloud", "identityClient": { "_withCredentials": false, "_httpClient": { "proxyAgents": {}, "keepAliveAgents": {}, "cookieJar": { "version": "tough-cookie@4.0.0", "storeType": "MemoryCookieStore", "rejectPublicSuffixes": false, "cookies": [] } }, "_requestPolicyOptions": {}, "_requestPolicyFactories": [ {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ], "authorityHost": "https://login.microsoftonline.com", "baseUri": "https://login.microsoftonline.com" }, "tenantId": "common" } ] } ``` **To Reproduce** Steps to reproduce the behavior: 1. Login on Azure Account extension 2. Install @azure/identity@1.3.0 3. Login to your azure account 4. new DefaultAzureCredential() **Expected behavior** I expect to receive a credential since I'm logged into the extension. **Screenshots** Just "Proof" that I'm logged into the extension: ![image](https://user-images.githubusercontent.com/14295455/119995695-24699700-bfce-11eb-89ed-16b435d1b11f.png) **Additional context** I'm also logged into the CLI. I have access to several subscriptions. I have not configured ANY environment variables (not needed?) When running `VisualStudioCodeCredential()` directly I get this back: ```js { "cloudName": "AzureCloud", "identityClient": { "_withCredentials": false, "_httpClient": { "proxyAgents": {}, "keepAliveAgents": {}, "cookieJar": { "version": "tough-cookie@4.0.0", "storeType": "MemoryCookieStore", "rejectPublicSuffixes": false, "cookies": [] } }, "_requestPolicyOptions": {}, "_requestPolicyFactories": [ {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ], "authorityHost": "https://login.microsoftonline.com", "baseUri": "https://login.microsoftonline.com" }, "tenantId": "common" } ```
Author: Crafoord
Assignees: sadasant
Labels: `App Configuration`, `Azure.Identity`, `Service Attention`, `customer-reported`, `needs-team-attention`, `needs-triage`, `question`
Milestone: -
HarshaNalluru commented 3 years ago

/cc @pakrym

sadasant commented 3 years ago

@Crafoord just to confirm,

When you said:

My testing flow (I waited 5-10 minutes between each test after changing role assignments):

  1. Be "Owner" through ad group -> does not work 👎
  2. Be "App Configuration Data Owner" directly on my user -> works 👍
  3. Be "Owner" directly on my user -> works 👍
  4. Be "Owner" through ad group -> does not work 👎

Did you try setting "App Configuration Data Owner" directly on the AD group? The list doesn’t include that.

Crafoord commented 3 years ago

@sadasant

I never tried setting anything directly on the AD group. But I tried it now (adding "App Configuration Data Owner" to my one of my groups) and it worked after a while.

This worked (access for ad group on app-config): image

So maybe something with scope that is acting up?

sadasant commented 3 years ago

@Crafoord that seems to be working as expected:

So, perhaps this was a documentation issue? cc: @HarshaNalluru

HarshaNalluru commented 3 years ago

For the data access, you'd need the "App Configuration Data Owner" role. https://docs.microsoft.com/en-us/azure/azure-app-configuration/concept-enable-rbac#azure-built-in-roles-for-azure-app-configuration

Do you have anything to add about the differences with "Owner" role w.r.t AD group vs a user, @zhenlan?

zhenlan commented 3 years ago

Adding "Owner" directly on user -> works.

If all you have is the "Owner" role on App Config, it should NOT work. You can actually go to Azure Portal Configuration explorer and switch to using Azure AD authentication to test out easily.

Do you have anything to add about the differences with "Owner" role w.r.t AD group vs a user, @zhenlan?

Similar to the "Contributor" role, the "Owner" role allows you to manage the App Configuration resource. While the App Configuration data can be accessed using access keys, this role does not grant direct access to the data using Azure AD. It doesn't matter whether you are assigned the role directly or you are in a group that is assigned the role.

HarshaNalluru commented 3 years ago

Thanks for the docs update, @zhenlan.

Do you have any follow-up questions, @Crafoord?

Crafoord commented 3 years ago

Thanks all for the help!

The only "question" (maybe more feedback?) is this:

If I can see the keys of an app-config in the portal when logged in as myself, I would expect my credentials to be able to do the same thing when being logged in from my dev environment.

Does that make sense?

Regards

zhenlan commented 3 years ago

@Crafoord App Configuration supports 2 authentication methods: access key and Azure AD. When you test in Azure Portal, you want to make sure you use the same authentication method as what your code will be using.

image

ghost commented 3 years ago

Hi, we're sending this friendly reminder because we haven't heard back from you in a while. We need more information about this issue to help address it. Please be sure to give us your input within the next 7 days. If we don't hear back from you within 14 days of this comment the issue will be automatically closed. Thank you!