@azure/identity 2.0.0-beta.5 → 2.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @azure/identity might be problematic. Click here for more details.
- package/CHANGELOG.md +49 -10
- package/README.md +26 -21
- package/dist/index.js +461 -211
- package/dist/index.js.map +1 -1
- package/dist-esm/src/client/errors.js +1 -1
- package/dist-esm/src/client/errors.js.map +1 -1
- package/dist-esm/src/client/identityClient.js +2 -6
- package/dist-esm/src/client/identityClient.js.map +1 -1
- package/dist-esm/src/credentials/applicationCredential.js +0 -3
- package/dist-esm/src/credentials/applicationCredential.js.map +1 -1
- package/dist-esm/src/credentials/authorizationCodeCredential.js +12 -76
- package/dist-esm/src/credentials/authorizationCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/chainedTokenCredential.js +4 -3
- package/dist-esm/src/credentials/chainedTokenCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientCertificateCredential.js +3 -0
- package/dist-esm/src/credentials/clientCertificateCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredential.browser.js +1 -4
- package/dist-esm/src/credentials/clientSecretCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredential.js +3 -0
- package/dist-esm/src/credentials/clientSecretCredential.js.map +1 -1
- package/dist-esm/src/credentials/credentialPersistenceOptions.js.map +1 -1
- package/dist-esm/src/credentials/defaultAzureCredential.js +5 -8
- package/dist-esm/src/credentials/defaultAzureCredential.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js +21 -10
- package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js +23 -12
- package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js +22 -11
- package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js +19 -7
- package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js +29 -20
- package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/index.js +13 -10
- package/dist-esm/src/credentials/managedIdentityCredential/index.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/models.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js +82 -0
- package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -0
- package/dist-esm/src/credentials/managedIdentityCredential/utils.js +10 -5
- package/dist-esm/src/credentials/managedIdentityCredential/utils.js.map +1 -1
- package/dist-esm/src/credentials/onBehalfOfCredential.browser.js +17 -0
- package/dist-esm/src/credentials/onBehalfOfCredential.browser.js.map +1 -0
- package/dist-esm/src/credentials/onBehalfOfCredential.js +62 -0
- package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -0
- package/dist-esm/src/credentials/{visualStudioCodeCredentialExtension.js → onBehalfOfCredentialOptions.js} +1 -1
- package/dist-esm/src/credentials/onBehalfOfCredentialOptions.js.map +1 -0
- package/dist-esm/src/credentials/usernamePasswordCredential.browser.js +10 -13
- package/dist-esm/src/credentials/usernamePasswordCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/usernamePasswordCredential.js +3 -0
- package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
- package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js +1 -1
- package/dist-esm/src/credentials/visualStudioCodeCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/visualStudioCodeCredential.js +11 -1
- package/dist-esm/src/credentials/visualStudioCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js +4 -0
- package/dist-esm/src/credentials/visualStudioCodeCredentialPlugin.js.map +1 -0
- package/dist-esm/src/index.js +2 -1
- package/dist-esm/src/index.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +41 -0
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +1 -0
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +48 -29
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +56 -0
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +1 -0
- package/dist-esm/src/msal/nodeFlows/nodeCommon.js +6 -1
- package/dist-esm/src/msal/nodeFlows/nodeCommon.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/tokenCachePersistenceOptions.js.map +1 -1
- package/dist-esm/src/plugins/consumer.browser.js +7 -0
- package/dist-esm/src/plugins/consumer.browser.js.map +1 -0
- package/dist-esm/src/{extensions → plugins}/consumer.js +12 -12
- package/dist-esm/src/plugins/consumer.js.map +1 -0
- package/dist-esm/src/{extensions → plugins}/provider.js +0 -0
- package/dist-esm/src/plugins/provider.js.map +1 -0
- package/package.json +10 -12
- package/types/identity.d.ts +126 -41
- package/dist-esm/src/credentials/visualStudioCodeCredentialExtension.js.map +0 -1
- package/dist-esm/src/extensions/consumer.browser.js +0 -7
- package/dist-esm/src/extensions/consumer.browser.js.map +0 -1
- package/dist-esm/src/extensions/consumer.js.map +0 -1
- package/dist-esm/src/extensions/provider.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaultAzureCredential.js","sourceRoot":"","sources":["../../../src/credentials/defaultAzureCredential.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAMlC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AA4B1E;;;;;GAKG;AACH,MAAM,OAAO,gCAAiC,SAAQ,yBAAyB;IAC7E,YAAY,OAAuC;;QACjD,MAAM,uBAAuB,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,uBAAuB,mCAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAChG,IAAI,uBAAuB,KAAK,SAAS,EAAE;YACzC,KAAK,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;SACzC;aAAM;YACL,KAAK,CAAC,OAAO,CAAC,CAAC;SAChB;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAmC;IAChE,qBAAqB;IACrB,gCAAgC;IAChC,0BAA0B;IAC1B,kBAAkB;IAClB,yBAAyB;CAC1B,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"defaultAzureCredential.js","sourceRoot":"","sources":["../../../src/credentials/defaultAzureCredential.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAMlC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AA4B1E;;;;;GAKG;AACH,MAAM,OAAO,gCAAiC,SAAQ,yBAAyB;IAC7E,YAAY,OAAuC;;QACjD,MAAM,uBAAuB,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,uBAAuB,mCAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAChG,IAAI,uBAAuB,KAAK,SAAS,EAAE;YACzC,KAAK,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;SACzC;aAAM;YACL,KAAK,CAAC,OAAO,CAAC,CAAC;SAChB;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAmC;IAChE,qBAAqB;IACrB,gCAAgC;IAChC,0BAA0B;IAC1B,kBAAkB;IAClB,yBAAyB;CAC1B,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,sBAAuB,SAAQ,sBAAsB;IAChE;;;;;;;;;OASG;IACH,YAAY,OAAuC;QACjD,KAAK,CAAC,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,kBAAkB;YACrB,oFAAoF,CAAC;IACzF,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { TokenCredential } from \"@azure/core-auth\";\n\nimport { TokenCredentialOptions } from \"../client/identityClient\";\n\nimport { ChainedTokenCredential } from \"./chainedTokenCredential\";\n\nimport { AzureCliCredential } from \"./azureCliCredential\";\nimport { AzurePowerShellCredential } from \"./azurePowerShellCredential\";\nimport { EnvironmentCredential } from \"./environmentCredential\";\nimport { ManagedIdentityCredential } from \"./managedIdentityCredential\";\nimport { CredentialPersistenceOptions } from \"./credentialPersistenceOptions\";\nimport { VisualStudioCodeCredential } from \"./visualStudioCodeCredential\";\n\n/**\n * Provides options to configure the {@link DefaultAzureCredential} class.\n */\nexport interface DefaultAzureCredentialOptions\n extends TokenCredentialOptions,\n CredentialPersistenceOptions {\n /**\n * Optionally pass in a Tenant ID to be used as part of the credential.\n * By default it may use a generic tenant ID depending on the underlying credential.\n */\n tenantId?: string;\n /**\n * Optionally pass in a user assigned client ID to be used by the {@link ManagedIdentityCredential}.\n * This client ID can also be passed through to the {@link ManagedIdentityCredential} through the environment variable: AZURE_CLIENT_ID.\n */\n managedIdentityClientId?: string;\n}\n\n/**\n * The type of a class that implements TokenCredential and accepts\n * `DefaultAzureCredentialOptions`.\n */\ninterface DefaultCredentialConstructor {\n new (options?: DefaultAzureCredentialOptions): TokenCredential;\n}\n\n/**\n * A shim around ManagedIdentityCredential that adapts it to accept\n * `DefaultAzureCredentialOptions`.\n *\n * @internal\n */\nexport class DefaultManagedIdentityCredential extends ManagedIdentityCredential {\n constructor(options?: DefaultAzureCredentialOptions) {\n const managedIdentityClientId = options?.managedIdentityClientId ?? process.env.AZURE_CLIENT_ID;\n if (managedIdentityClientId !== undefined) {\n super(managedIdentityClientId, options);\n } else {\n super(options);\n }\n }\n}\n\nexport const defaultCredentials: DefaultCredentialConstructor[] = [\n EnvironmentCredential,\n DefaultManagedIdentityCredential,\n VisualStudioCodeCredential,\n AzureCliCredential,\n AzurePowerShellCredential\n];\n\n/**\n * Provides a default {@link ChainedTokenCredential} configuration that should\n * work for most applications that use the Azure SDK. The following credential\n * types will be tried, in order:\n *\n * - {@link EnvironmentCredential}\n * - {@link ManagedIdentityCredential}\n * - {@link VisualStudioCodeCredential}\n * - {@link AzureCliCredential}\n * - {@link AzurePowerShellCredential}\n *\n * Consult the documentation of these credential types for more information\n * on how they attempt authentication.\n */\nexport class DefaultAzureCredential extends ChainedTokenCredential {\n /**\n * Creates an instance of the DefaultAzureCredential class.\n *\n * **Note**: `VisualStudioCodeCredential` is provided by a plugin package:\n * `@azure/identity-vscode`. If this package is not installed and registered\n * using the plugin API (`useIdentityPlugin`), then authentication using\n * `VisualStudioCodeCredential` will not be available.\n *\n * @param options - Optional parameters. See {@link DefaultAzureCredentialOptions}.\n */\n constructor(options?: DefaultAzureCredentialOptions) {\n super(...defaultCredentials.map((ctor) => new ctor(options)));\n this.UnavailableMessage =\n \"DefaultAzureCredential => failed to retrieve a token from the included credentials\";\n }\n}\n"]}
|
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
// Licensed under the MIT license.
|
|
3
3
|
import { createHttpHeaders } from "@azure/core-rest-pipeline";
|
|
4
4
|
import { credentialLogger } from "../../util/logging";
|
|
5
|
-
import { msiGenericGetToken } from "./utils";
|
|
6
|
-
const
|
|
5
|
+
import { mapScopesToResource, msiGenericGetToken } from "./utils";
|
|
6
|
+
const msiName = "ManagedIdentityCredential - AppServiceMSI 2017";
|
|
7
|
+
const logger = credentialLogger(msiName);
|
|
7
8
|
function expiresInParser(requestBody) {
|
|
8
9
|
// Parse a date format like "06/20/2019 02:57:58 +00:00" and
|
|
9
10
|
// convert it into a JavaScript-formatted date
|
|
10
11
|
return Date.parse(requestBody.expires_on);
|
|
11
12
|
}
|
|
12
|
-
function prepareRequestOptions(
|
|
13
|
+
function prepareRequestOptions(scopes, clientId) {
|
|
14
|
+
const resource = mapScopesToResource(scopes);
|
|
15
|
+
if (!resource) {
|
|
16
|
+
throw new Error(`${msiName}: Multiple scopes are not supported.`);
|
|
17
|
+
}
|
|
13
18
|
const queryParameters = {
|
|
14
19
|
resource,
|
|
15
20
|
"api-version": "2017-09-01"
|
|
@@ -20,10 +25,10 @@ function prepareRequestOptions(resource, clientId) {
|
|
|
20
25
|
const query = new URLSearchParams(queryParameters);
|
|
21
26
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
22
27
|
if (!process.env.MSI_ENDPOINT) {
|
|
23
|
-
throw new Error(
|
|
28
|
+
throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
|
|
24
29
|
}
|
|
25
30
|
if (!process.env.MSI_SECRET) {
|
|
26
|
-
throw new Error(
|
|
31
|
+
throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);
|
|
27
32
|
}
|
|
28
33
|
return {
|
|
29
34
|
url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,
|
|
@@ -35,17 +40,23 @@ function prepareRequestOptions(resource, clientId) {
|
|
|
35
40
|
};
|
|
36
41
|
}
|
|
37
42
|
export const appServiceMsi2017 = {
|
|
38
|
-
async isAvailable() {
|
|
43
|
+
async isAvailable(scopes) {
|
|
44
|
+
const resource = mapScopesToResource(scopes);
|
|
45
|
+
if (!resource) {
|
|
46
|
+
logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
39
49
|
const env = process.env;
|
|
40
50
|
const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);
|
|
41
51
|
if (!result) {
|
|
42
|
-
logger.info(
|
|
52
|
+
logger.info(`${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`);
|
|
43
53
|
}
|
|
44
54
|
return result;
|
|
45
55
|
},
|
|
46
|
-
async getToken(
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
57
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
58
|
+
logger.info(`${msiName}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`);
|
|
59
|
+
return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
|
|
49
60
|
}
|
|
50
61
|
};
|
|
51
62
|
//# sourceMappingURL=appServiceMsi2017.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appServiceMsi2017.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/appServiceMsi2017.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"appServiceMsi2017.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/appServiceMsi2017.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;AAEtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElE,MAAM,OAAO,GAAG,gDAAgD,CAAC;AACjE,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAEzC,SAAS,eAAe,CAAC,WAAgB;IACvC,4DAA4D;IAC5D,8CAA8C;IAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,qBAAqB,CAC5B,MAAyB,EACzB,QAAiB;IAEjB,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,sCAAsC,CAAC,CAAC;KACnE;IAED,MAAM,eAAe,GAAQ;QAC3B,QAAQ;QACR,aAAa,EAAE,YAAY;KAC5B,CAAC;IAEF,IAAI,QAAQ,EAAE;QACZ,eAAe,CAAC,QAAQ,GAAG,QAAQ,CAAC;KACrC;IAED,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,eAAe,CAAC,CAAC;IAEnD,wIAAwI;IACxI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,8CAA8C,CAAC,CAAC;KAC3E;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,4CAA4C,CAAC,CAAC;KACzE;IAED,OAAO;QACL,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE;QACtD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,iBAAiB,CAAC;YACzB,MAAM,EAAE,kBAAkB;YAC1B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;SAC/B,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAQ;IACpC,KAAK,CAAC,WAAW,CAAC,MAAM;QACtB,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,mDAAmD,CAAC,CAAC;YAC3E,OAAO,KAAK,CAAC;SACd;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,mFAAmF,CAC9F,CAAC;SACH;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,aAA+B,EAC/B,kBAAmC,EAAE;QAErC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;QAE3D,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,2FAA2F,OAAO,CAAC,GAAG,CAAC,YAAY,6BAA6B,CAC3J,CAAC;QAEF,OAAO,kBAAkB,CACvB,cAAc,EACd,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,EACvC,eAAe,EACf,eAAe,CAChB,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\n\nconst msiName = \"ManagedIdentityCredential - AppServiceMSI 2017\";\nconst logger = credentialLogger(msiName);\n\nfunction expiresInParser(requestBody: any): number {\n // Parse a date format like \"06/20/2019 02:57:58 +00:00\" and\n // convert it into a JavaScript-formatted date\n return Date.parse(requestBody.expires_on);\n}\n\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientId?: string\n): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n\n const queryParameters: any = {\n resource,\n \"api-version\": \"2017-09-01\"\n };\n\n if (clientId) {\n queryParameters.clientid = clientId;\n }\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.MSI_ENDPOINT) {\n throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);\n }\n if (!process.env.MSI_SECRET) {\n throw new Error(`${msiName}: Missing environment variable: MSI_SECRET`);\n }\n\n return {\n url: `${process.env.MSI_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n secret: process.env.MSI_SECRET\n })\n };\n}\n\nexport const appServiceMsi2017: MSI = {\n async isAvailable(scopes): Promise<boolean> {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n return false;\n }\n const env = process.env;\n const result = Boolean(env.MSI_ENDPOINT && env.MSI_SECRET);\n if (!result) {\n logger.info(\n `${msiName}: Unavailable. The environment variables needed are: MSI_ENDPOINT and MSI_SECRET.`\n );\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(\n `${msiName}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].`\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(scopes, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
|
|
@@ -3,13 +3,18 @@
|
|
|
3
3
|
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
4
4
|
import { readFile } from "fs";
|
|
5
5
|
import { credentialLogger } from "../../util/logging";
|
|
6
|
-
import { msiGenericGetToken } from "./utils";
|
|
6
|
+
import { mapScopesToResource, msiGenericGetToken } from "./utils";
|
|
7
7
|
import { azureArcAPIVersion } from "./constants";
|
|
8
8
|
import { AuthenticationError } from "../../client/errors";
|
|
9
|
-
const
|
|
9
|
+
const msiName = "ManagedIdentityCredential - Azure Arc MSI";
|
|
10
|
+
const logger = credentialLogger(msiName);
|
|
10
11
|
// Azure Arc MSI doesn't have a special expiresIn parser.
|
|
11
12
|
const expiresInParser = undefined;
|
|
12
|
-
function prepareRequestOptions(
|
|
13
|
+
function prepareRequestOptions(scopes) {
|
|
14
|
+
const resource = mapScopesToResource(scopes);
|
|
15
|
+
if (!resource) {
|
|
16
|
+
throw new Error(`${msiName}: Multiple scopes are not supported.`);
|
|
17
|
+
}
|
|
13
18
|
const queryParameters = {
|
|
14
19
|
resource,
|
|
15
20
|
"api-version": azureArcAPIVersion
|
|
@@ -17,7 +22,7 @@ function prepareRequestOptions(resource) {
|
|
|
17
22
|
const query = new URLSearchParams(queryParameters);
|
|
18
23
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
19
24
|
if (!process.env.IDENTITY_ENDPOINT) {
|
|
20
|
-
throw new Error(
|
|
25
|
+
throw new Error(`${msiName}: Missing environment variable: IDENTITY_ENDPOINT`);
|
|
21
26
|
}
|
|
22
27
|
return createPipelineRequest({
|
|
23
28
|
// Should be similar to: http://localhost:40342/metadata/identity/oauth2/token
|
|
@@ -45,7 +50,7 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
|
|
|
45
50
|
if (response.bodyAsText) {
|
|
46
51
|
message = ` Response: ${response.bodyAsText}`;
|
|
47
52
|
}
|
|
48
|
-
throw new AuthenticationError(response.status,
|
|
53
|
+
throw new AuthenticationError(response.status, `${msiName}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`);
|
|
49
54
|
}
|
|
50
55
|
const authHeader = response.headers.get("www-authenticate") || "";
|
|
51
56
|
try {
|
|
@@ -56,23 +61,29 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
|
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
export const arcMsi = {
|
|
59
|
-
async isAvailable() {
|
|
64
|
+
async isAvailable(scopes) {
|
|
65
|
+
const resource = mapScopesToResource(scopes);
|
|
66
|
+
if (!resource) {
|
|
67
|
+
logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
60
70
|
const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);
|
|
61
71
|
if (!result) {
|
|
62
|
-
logger.info(
|
|
72
|
+
logger.info(`${msiName}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`);
|
|
63
73
|
}
|
|
64
74
|
return result;
|
|
65
75
|
},
|
|
66
|
-
async getToken(
|
|
76
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
67
77
|
var _a;
|
|
68
|
-
|
|
78
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
79
|
+
logger.info(`${msiName}: Authenticating.`);
|
|
69
80
|
if (clientId) {
|
|
70
|
-
throw new Error(
|
|
81
|
+
throw new Error(`${msiName}: User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity, omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.`);
|
|
71
82
|
}
|
|
72
|
-
const requestOptions = Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal,
|
|
83
|
+
const requestOptions = Object.assign(Object.assign({ disableJsonStringifyOnBody: true, deserializationMapper: undefined, abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions(scopes)), { allowInsecureConnection: true });
|
|
73
84
|
const filePath = await filePathRequest(identityClient, requestOptions);
|
|
74
85
|
if (!filePath) {
|
|
75
|
-
throw new Error(
|
|
86
|
+
throw new Error(`${msiName}: Failed to find the token file.`);
|
|
76
87
|
}
|
|
77
88
|
const key = await readFileAsync(filePath, { encoding: "utf-8" });
|
|
78
89
|
(_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arcMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/arcMsi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"arcMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/arcMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n createHttpHeaders,\n createPipelineRequest,\n PipelineRequestOptions\n} from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { readFile } from \"fs\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { IdentityClient } from \"../../client/identityClient\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\nimport { azureArcAPIVersion } from \"./constants\";\nimport { AuthenticationError } from \"../../client/errors\";\n\nconst msiName = \"ManagedIdentityCredential - Azure Arc MSI\";\nconst logger = credentialLogger(msiName);\n\n// Azure Arc MSI doesn't have a special expiresIn parser.\nconst expiresInParser = undefined;\n\nfunction prepareRequestOptions(scopes: string | string[]): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n const queryParameters: any = {\n resource,\n \"api-version\": azureArcAPIVersion\n };\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.IDENTITY_ENDPOINT) {\n throw new Error(`${msiName}: Missing environment variable: IDENTITY_ENDPOINT`);\n }\n\n return createPipelineRequest({\n // Should be similar to: http://localhost:40342/metadata/identity/oauth2/token\n url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Metadata: \"true\"\n })\n });\n}\n\n// Since \"fs\"'s readFileSync locks the thread, and to avoid extra dependencies.\nfunction readFileAsync(path: string, options: { encoding: string }): Promise<string> {\n return new Promise((resolve, reject) =>\n readFile(path, options, (err, data) => {\n if (err) {\n reject(err);\n }\n resolve(data);\n })\n );\n}\n\nasync function filePathRequest(\n identityClient: IdentityClient,\n requestPrepareOptions: PipelineRequestOptions\n): Promise<string | undefined> {\n const response = await identityClient.sendRequest(createPipelineRequest(requestPrepareOptions));\n\n if (response.status !== 401) {\n let message = \"\";\n if (response.bodyAsText) {\n message = ` Response: ${response.bodyAsText}`;\n }\n throw new AuthenticationError(\n response.status,\n `${msiName}: To authenticate with Azure Arc MSI, status code 401 is expected on the first request. ${message}`\n );\n }\n\n const authHeader = response.headers.get(\"www-authenticate\") || \"\";\n try {\n return authHeader.split(\"=\").slice(1)[0];\n } catch (e) {\n throw Error(`Invalid www-authenticate header format: ${authHeader}`);\n }\n}\n\nexport const arcMsi: MSI = {\n async isAvailable(scopes): Promise<boolean> {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n return false;\n }\n const result = Boolean(process.env.IMDS_ENDPOINT && process.env.IDENTITY_ENDPOINT);\n if (!result) {\n logger.info(\n `${msiName}: The environment variables needed are: IMDS_ENDPOINT and IDENTITY_ENDPOINT`\n );\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(`${msiName}: Authenticating.`);\n\n if (clientId) {\n throw new Error(\n `${msiName}: User assigned identity is not supported by the Azure Arc Managed Identity Endpoint. To authenticate with the system assigned identity, omit the client id when constructing the ManagedIdentityCredential, or if authenticating with the DefaultAzureCredential ensure the AZURE_CLIENT_ID environment variable is not set.`\n );\n }\n\n const requestOptions = {\n disableJsonStringifyOnBody: true,\n deserializationMapper: undefined,\n abortSignal: getTokenOptions.abortSignal,\n ...prepareRequestOptions(scopes),\n allowInsecureConnection: true\n };\n\n const filePath = await filePathRequest(identityClient, requestOptions);\n\n if (!filePath) {\n throw new Error(`${msiName}: Failed to find the token file.`);\n }\n\n const key = await readFileAsync(filePath, { encoding: \"utf-8\" });\n requestOptions.headers?.set(\"Authorization\", `Basic ${key}`);\n\n return msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions);\n }\n};\n"]}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT license.
|
|
3
|
-
import qs from "qs";
|
|
4
3
|
import { createHttpHeaders } from "@azure/core-rest-pipeline";
|
|
5
4
|
import { credentialLogger } from "../../util/logging";
|
|
6
|
-
import { msiGenericGetToken } from "./utils";
|
|
7
|
-
const
|
|
5
|
+
import { mapScopesToResource, msiGenericGetToken } from "./utils";
|
|
6
|
+
const msiName = "ManagedIdentityCredential - CloudShellMSI";
|
|
7
|
+
const logger = credentialLogger(msiName);
|
|
8
8
|
// Cloud Shell MSI doesn't have a special expiresIn parser.
|
|
9
9
|
const expiresInParser = undefined;
|
|
10
|
-
function prepareRequestOptions(
|
|
10
|
+
function prepareRequestOptions(scopes, clientId) {
|
|
11
|
+
const resource = mapScopesToResource(scopes);
|
|
12
|
+
if (!resource) {
|
|
13
|
+
throw new Error(`${msiName}: Multiple scopes are not supported.`);
|
|
14
|
+
}
|
|
11
15
|
const body = {
|
|
12
16
|
resource
|
|
13
17
|
};
|
|
@@ -16,12 +20,13 @@ function prepareRequestOptions(resource, clientId) {
|
|
|
16
20
|
}
|
|
17
21
|
// This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.
|
|
18
22
|
if (!process.env.MSI_ENDPOINT) {
|
|
19
|
-
throw new Error(
|
|
23
|
+
throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);
|
|
20
24
|
}
|
|
25
|
+
const params = new URLSearchParams(body);
|
|
21
26
|
return {
|
|
22
27
|
url: process.env.MSI_ENDPOINT,
|
|
23
28
|
method: "POST",
|
|
24
|
-
body:
|
|
29
|
+
body: params.toString(),
|
|
25
30
|
headers: createHttpHeaders({
|
|
26
31
|
Accept: "application/json",
|
|
27
32
|
Metadata: "true",
|
|
@@ -30,16 +35,22 @@ function prepareRequestOptions(resource, clientId) {
|
|
|
30
35
|
};
|
|
31
36
|
}
|
|
32
37
|
export const cloudShellMsi = {
|
|
33
|
-
async isAvailable() {
|
|
38
|
+
async isAvailable(scopes) {
|
|
39
|
+
const resource = mapScopesToResource(scopes);
|
|
40
|
+
if (!resource) {
|
|
41
|
+
logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
34
44
|
const result = Boolean(process.env.MSI_ENDPOINT);
|
|
35
45
|
if (!result) {
|
|
36
|
-
logger.info(
|
|
46
|
+
logger.info(`${msiName}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);
|
|
37
47
|
}
|
|
38
48
|
return result;
|
|
39
49
|
},
|
|
40
|
-
async getToken(
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
51
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
52
|
+
logger.info(`${msiName}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
|
|
53
|
+
return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
|
|
43
54
|
}
|
|
44
55
|
};
|
|
45
56
|
//# sourceMappingURL=cloudShellMsi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudShellMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/cloudShellMsi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cloudShellMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/cloudShellMsi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;AAGtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElE,MAAM,OAAO,GAAG,2CAA2C,CAAC;AAC5D,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAEzC,2DAA2D;AAC3D,MAAM,eAAe,GAAG,SAAS,CAAC;AAElC,SAAS,qBAAqB,CAC5B,MAAyB,EACzB,QAAiB;IAEjB,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,sCAAsC,CAAC,CAAC;KACnE;IAED,MAAM,IAAI,GAAQ;QAChB,QAAQ;KACT,CAAC;IAEF,IAAI,QAAQ,EAAE;QACZ,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;KAC3B;IAED,wIAAwI;IACxI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,8CAA8C,CAAC,CAAC;KAC3E;IACD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO;QACL,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QAC7B,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE;QACvB,OAAO,EAAE,iBAAiB,CAAC;YACzB,MAAM,EAAE,kBAAkB;YAC1B,QAAQ,EAAE,MAAM;YAChB,cAAc,EAAE,mCAAmC;SACpD,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAQ;IAChC,KAAK,CAAC,WAAW,CAAC,MAAM;QACtB,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,mDAAmD,CAAC,CAAC;YAC3E,OAAO,KAAK,CAAC;SACd;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,iEAAiE,CAAC,CAAC;SAC1F;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,QAAQ,CACZ,aAA+B,EAC/B,kBAAmC,EAAE;QAErC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC;QAE3D,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,4EAA4E,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,CAClH,CAAC;QAEF,OAAO,kBAAkB,CACvB,cAAc,EACd,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,EACvC,eAAe,EACf,eAAe,CAChB,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\n\nconst msiName = \"ManagedIdentityCredential - CloudShellMSI\";\nconst logger = credentialLogger(msiName);\n\n// Cloud Shell MSI doesn't have a special expiresIn parser.\nconst expiresInParser = undefined;\n\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientId?: string\n): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n\n const body: any = {\n resource\n };\n\n if (clientId) {\n body.client_id = clientId;\n }\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.MSI_ENDPOINT) {\n throw new Error(`${msiName}: Missing environment variable: MSI_ENDPOINT`);\n }\n const params = new URLSearchParams(body);\n return {\n url: process.env.MSI_ENDPOINT,\n method: \"POST\",\n body: params.toString(),\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Metadata: \"true\",\n \"Content-Type\": \"application/x-www-form-urlencoded\"\n })\n };\n}\n\nexport const cloudShellMsi: MSI = {\n async isAvailable(scopes): Promise<boolean> {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n return false;\n }\n const result = Boolean(process.env.MSI_ENDPOINT);\n if (!result) {\n logger.info(`${msiName}: Unavailable. The environment variable MSI_ENDPOINT is needed.`);\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(\n `${msiName}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(scopes, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
|
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
// Licensed under the MIT license.
|
|
3
3
|
import { createHttpHeaders } from "@azure/core-rest-pipeline";
|
|
4
4
|
import { credentialLogger } from "../../util/logging";
|
|
5
|
-
import { msiGenericGetToken } from "./utils";
|
|
5
|
+
import { mapScopesToResource, msiGenericGetToken } from "./utils";
|
|
6
6
|
import { azureFabricVersion } from "./constants";
|
|
7
|
-
const
|
|
7
|
+
const msiName = "ManagedIdentityCredential - Fabric MSI";
|
|
8
|
+
const logger = credentialLogger(msiName);
|
|
8
9
|
function expiresInParser(requestBody) {
|
|
9
10
|
// Parses a string representation of the seconds since epoch into a number value
|
|
10
11
|
return Number(requestBody.expires_on);
|
|
11
12
|
}
|
|
12
|
-
function prepareRequestOptions(
|
|
13
|
+
function prepareRequestOptions(scopes, clientId) {
|
|
14
|
+
const resource = mapScopesToResource(scopes);
|
|
15
|
+
if (!resource) {
|
|
16
|
+
throw new Error(`${msiName}: Multiple scopes are not supported.`);
|
|
17
|
+
}
|
|
13
18
|
const queryParameters = {
|
|
14
19
|
resource,
|
|
15
20
|
"api-version": azureFabricVersion
|
|
@@ -45,22 +50,29 @@ function prepareRequestOptions(resource, clientId) {
|
|
|
45
50
|
// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER"
|
|
46
51
|
//
|
|
47
52
|
export const fabricMsi = {
|
|
48
|
-
async isAvailable() {
|
|
53
|
+
async isAvailable(scopes) {
|
|
54
|
+
const resource = mapScopesToResource(scopes);
|
|
55
|
+
if (!resource) {
|
|
56
|
+
logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
49
59
|
const env = process.env;
|
|
50
60
|
const result = Boolean(env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT);
|
|
51
61
|
if (!result) {
|
|
52
|
-
logger.info(
|
|
62
|
+
logger.info(`${msiName}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT, IDENTITY_HEADER and IDENTITY_SERVER_THUMBPRINT`);
|
|
53
63
|
}
|
|
54
64
|
return result;
|
|
55
65
|
},
|
|
56
|
-
async getToken(
|
|
66
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
67
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
57
68
|
logger.info([
|
|
69
|
+
`${msiName}:`,
|
|
58
70
|
"Using the endpoint and the secret coming from the environment variables:",
|
|
59
71
|
`IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,
|
|
60
72
|
"IDENTITY_HEADER=[REDACTED] and",
|
|
61
73
|
"IDENTITY_SERVER_THUMBPRINT=[REDACTED]."
|
|
62
74
|
].join(" "));
|
|
63
|
-
return msiGenericGetToken(identityClient, prepareRequestOptions(
|
|
75
|
+
return msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
|
|
64
76
|
}
|
|
65
77
|
};
|
|
66
78
|
//# sourceMappingURL=fabricMsi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fabricMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/fabricMsi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAA0B,MAAM,2BAA2B,CAAC;AAGtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"fabricMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/fabricMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createHttpHeaders, PipelineRequestOptions } from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\nimport { azureFabricVersion } from \"./constants\";\n\nconst msiName = \"ManagedIdentityCredential - Fabric MSI\";\nconst logger = credentialLogger(msiName);\n\nfunction expiresInParser(requestBody: any): number {\n // Parses a string representation of the seconds since epoch into a number value\n return Number(requestBody.expires_on);\n}\n\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientId?: string\n): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n\n const queryParameters: any = {\n resource,\n \"api-version\": azureFabricVersion\n };\n\n if (clientId) {\n queryParameters.client_id = clientId;\n }\n\n const query = new URLSearchParams(queryParameters);\n\n // This error should not bubble up, since we verify that this environment variable is defined in the isAvailable() method defined below.\n if (!process.env.IDENTITY_ENDPOINT) {\n throw new Error(\"Missing environment variable: IDENTITY_ENDPOINT\");\n }\n if (!process.env.IDENTITY_HEADER) {\n throw new Error(\"Missing environment variable: IDENTITY_HEADER\");\n }\n\n return {\n url: `${process.env.IDENTITY_ENDPOINT}?${query.toString()}`,\n method: \"GET\",\n headers: createHttpHeaders({\n Accept: \"application/json\",\n Secret: process.env.IDENTITY_HEADER\n })\n };\n}\n\n// This credential can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:\n//\n// FROM node:12\n// RUN wget https://host.any/path/bash.sh\n// CMD [\"bash\", \"bash.sh\"]\n//\n// Where the bash script contains:\n//\n// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H \"Secret: $IDENTITY_HEADER\"\n//\n\nexport const fabricMsi: MSI = {\n async isAvailable(scopes): Promise<boolean> {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);\n return false;\n }\n const env = process.env;\n const result = Boolean(\n env.IDENTITY_ENDPOINT && env.IDENTITY_HEADER && env.IDENTITY_SERVER_THUMBPRINT\n );\n if (!result) {\n logger.info(\n `${msiName}: Unavailable. The environment variables needed are: IDENTITY_ENDPOINT, IDENTITY_HEADER and IDENTITY_SERVER_THUMBPRINT`\n );\n }\n return result;\n },\n async getToken(\n configuration: MSIConfiguration,\n getTokenOptions: GetTokenOptions = {}\n ): Promise<AccessToken | null> {\n const { identityClient, scopes, clientId } = configuration;\n\n logger.info(\n [\n `${msiName}:`,\n \"Using the endpoint and the secret coming from the environment variables:\",\n `IDENTITY_ENDPOINT=${process.env.IDENTITY_ENDPOINT},`,\n \"IDENTITY_HEADER=[REDACTED] and\",\n \"IDENTITY_SERVER_THUMBPRINT=[REDACTED].\"\n ].join(\" \")\n );\n\n return msiGenericGetToken(\n identityClient,\n prepareRequestOptions(scopes, clientId),\n expiresInParser,\n getTokenOptions\n );\n }\n};\n"]}
|
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT license.
|
|
3
|
-
import qs from "qs";
|
|
4
3
|
import { delay } from "@azure/core-util";
|
|
5
4
|
import { createHttpHeaders, createPipelineRequest, RestError } from "@azure/core-rest-pipeline";
|
|
6
5
|
import { SpanStatusCode } from "@azure/core-tracing";
|
|
7
6
|
import { credentialLogger } from "../../util/logging";
|
|
8
7
|
import { createSpan } from "../../util/tracing";
|
|
9
8
|
import { imdsApiVersion, imdsEndpointPath, imdsHost } from "./constants";
|
|
10
|
-
import { msiGenericGetToken } from "./utils";
|
|
9
|
+
import { mapScopesToResource, msiGenericGetToken } from "./utils";
|
|
11
10
|
import { AuthenticationError } from "../../client/errors";
|
|
12
|
-
const
|
|
11
|
+
const msiName = "ManagedIdentityCredential - IMDS";
|
|
12
|
+
const logger = credentialLogger(msiName);
|
|
13
13
|
function expiresInParser(requestBody) {
|
|
14
14
|
if (requestBody.expires_on) {
|
|
15
15
|
// Use the expires_on timestamp if it's available
|
|
16
16
|
const expires = +requestBody.expires_on * 1000;
|
|
17
|
-
logger.info(
|
|
17
|
+
logger.info(`${msiName}: IMDS using expires_on: ${expires} (original value: ${requestBody.expires_on})`);
|
|
18
18
|
return expires;
|
|
19
19
|
}
|
|
20
20
|
else {
|
|
21
21
|
// If these aren't possible, use expires_in and calculate a timestamp
|
|
22
22
|
const expires = Date.now() + requestBody.expires_in * 1000;
|
|
23
|
-
logger.info(
|
|
23
|
+
logger.info(`${msiName}: IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`);
|
|
24
24
|
return expires;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
function prepareRequestOptions(
|
|
27
|
+
function prepareRequestOptions(scopes, clientId) {
|
|
28
28
|
var _a;
|
|
29
|
+
const resource = mapScopesToResource(scopes);
|
|
30
|
+
if (!resource) {
|
|
31
|
+
throw new Error(`${msiName}: Multiple scopes are not supported.`);
|
|
32
|
+
}
|
|
29
33
|
const queryParameters = {
|
|
30
34
|
resource,
|
|
31
35
|
"api-version": imdsApiVersion
|
|
@@ -33,7 +37,8 @@ function prepareRequestOptions(resource, clientId) {
|
|
|
33
37
|
if (clientId) {
|
|
34
38
|
queryParameters.client_id = clientId;
|
|
35
39
|
}
|
|
36
|
-
const
|
|
40
|
+
const params = new URLSearchParams(queryParameters);
|
|
41
|
+
const query = params.toString();
|
|
37
42
|
const url = new URL(imdsEndpointPath, (_a = process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) !== null && _a !== void 0 ? _a : imdsHost);
|
|
38
43
|
return {
|
|
39
44
|
url: `${url}?${query}`,
|
|
@@ -51,8 +56,13 @@ export const imdsMsiRetryConfig = {
|
|
|
51
56
|
intervalIncrement: 2
|
|
52
57
|
};
|
|
53
58
|
export const imdsMsi = {
|
|
54
|
-
async isAvailable(
|
|
59
|
+
async isAvailable(scopes, identityClient, clientId, getTokenOptions) {
|
|
55
60
|
var _a, _b;
|
|
61
|
+
const resource = mapScopesToResource(scopes);
|
|
62
|
+
if (!resource) {
|
|
63
|
+
logger.info(`${msiName}: Unavailable. Multiple scopes are not supported.`);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
56
66
|
const { span, updatedOptions: options } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
|
|
57
67
|
// if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
|
|
58
68
|
if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
|
|
@@ -65,10 +75,7 @@ export const imdsMsi = {
|
|
|
65
75
|
// IMDS endpoint
|
|
66
76
|
requestOptions.headers.delete("Metadata");
|
|
67
77
|
}
|
|
68
|
-
requestOptions.tracingOptions =
|
|
69
|
-
spanOptions: options.tracingOptions && options.tracingOptions.spanOptions,
|
|
70
|
-
tracingContext: options.tracingOptions && options.tracingOptions.tracingContext
|
|
71
|
-
};
|
|
78
|
+
requestOptions.tracingOptions = options.tracingOptions;
|
|
72
79
|
try {
|
|
73
80
|
// Create a request with a timeout since we expect that
|
|
74
81
|
// not having a "Metadata" header should cause an error to be
|
|
@@ -78,18 +85,19 @@ export const imdsMsi = {
|
|
|
78
85
|
// This MSI uses the imdsEndpoint to get the token, which only uses http://
|
|
79
86
|
request.allowInsecureConnection = true;
|
|
80
87
|
try {
|
|
81
|
-
logger.info(
|
|
88
|
+
logger.info(`${msiName}: Pinging the Azure IMDS endpoint`);
|
|
82
89
|
await identityClient.sendRequest(request);
|
|
83
90
|
}
|
|
84
91
|
catch (err) {
|
|
85
92
|
if ((err.name === "RestError" && err.code === RestError.REQUEST_SEND_ERROR) ||
|
|
86
93
|
err.name === "AbortError" ||
|
|
94
|
+
err.code === "ENETUNREACH" || // Network unreachable
|
|
87
95
|
err.code === "ECONNREFUSED" || // connection refused
|
|
88
96
|
err.code === "EHOSTDOWN" // host is down
|
|
89
97
|
) {
|
|
90
98
|
// If the request failed, or Node.js was unable to establish a connection,
|
|
91
99
|
// or the host was down, we'll assume the IMDS endpoint isn't available.
|
|
92
|
-
logger.info(
|
|
100
|
+
logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);
|
|
93
101
|
span.setStatus({
|
|
94
102
|
code: SpanStatusCode.ERROR,
|
|
95
103
|
message: err.message
|
|
@@ -98,13 +106,13 @@ export const imdsMsi = {
|
|
|
98
106
|
}
|
|
99
107
|
}
|
|
100
108
|
// If we received any response, the endpoint is available
|
|
101
|
-
logger.info(
|
|
109
|
+
logger.info(`${msiName}: The Azure IMDS endpoint is available`);
|
|
102
110
|
return true;
|
|
103
111
|
}
|
|
104
112
|
catch (err) {
|
|
105
113
|
// createWebResource failed.
|
|
106
114
|
// This error should bubble up to the user.
|
|
107
|
-
logger.info(
|
|
115
|
+
logger.info(`${msiName}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`);
|
|
108
116
|
span.setStatus({
|
|
109
117
|
code: SpanStatusCode.ERROR,
|
|
110
118
|
message: err.message
|
|
@@ -115,12 +123,13 @@ export const imdsMsi = {
|
|
|
115
123
|
span.end();
|
|
116
124
|
}
|
|
117
125
|
},
|
|
118
|
-
async getToken(
|
|
119
|
-
|
|
126
|
+
async getToken(configuration, getTokenOptions = {}) {
|
|
127
|
+
const { identityClient, scopes, clientId } = configuration;
|
|
128
|
+
logger.info(`${msiName}: Using the Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`);
|
|
120
129
|
let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;
|
|
121
130
|
for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {
|
|
122
131
|
try {
|
|
123
|
-
return await msiGenericGetToken(identityClient, prepareRequestOptions(
|
|
132
|
+
return await msiGenericGetToken(identityClient, prepareRequestOptions(scopes, clientId), expiresInParser, getTokenOptions);
|
|
124
133
|
}
|
|
125
134
|
catch (error) {
|
|
126
135
|
if (error.statusCode === 404) {
|
|
@@ -131,7 +140,7 @@ export const imdsMsi = {
|
|
|
131
140
|
throw error;
|
|
132
141
|
}
|
|
133
142
|
}
|
|
134
|
-
throw new AuthenticationError(404,
|
|
143
|
+
throw new AuthenticationError(404, `${msiName}: Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`);
|
|
135
144
|
}
|
|
136
145
|
};
|
|
137
146
|
//# sourceMappingURL=imdsMsi.js.map
|