@azure/identity 2.0.2-alpha.20211105.2 → 2.0.2-alpha.20211108.2
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/dist/index.js +166 -100
- package/dist/index.js.map +1 -1
- package/dist-esm/src/client/identityClient.js +1 -1
- package/dist-esm/src/client/identityClient.js.map +1 -1
- package/dist-esm/src/credentials/authorizationCodeCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/authorizationCodeCredential.js +1 -1
- package/dist-esm/src/credentials/authorizationCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/azureApplicationCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/azureApplicationCredential.js +1 -2
- package/dist-esm/src/credentials/azureApplicationCredential.js.map +1 -1
- package/dist-esm/src/credentials/azureCliCredential.js +1 -1
- package/dist-esm/src/credentials/azureCliCredential.js.map +1 -1
- package/dist-esm/src/credentials/azureCliCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/azurePowerShellCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/clientCertificateCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredential.browser.js +1 -1
- package/dist-esm/src/credentials/clientSecretCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/credentialPersistenceOptions.js.map +1 -1
- package/dist-esm/src/credentials/defaultAzureCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/defaultAzureCredential.js.map +1 -1
- package/dist-esm/src/credentials/environmentCredential.js +5 -4
- package/dist-esm/src/credentials/environmentCredential.js.map +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/interactiveCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js +18 -6
- package/dist-esm/src/credentials/managedIdentityCredential/appServiceMsi2017.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js +20 -6
- package/dist-esm/src/credentials/managedIdentityCredential/arcMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js +13 -5
- package/dist-esm/src/credentials/managedIdentityCredential/cloudShellMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/constants.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js +31 -16
- package/dist-esm/src/credentials/managedIdentityCredential/fabricMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js +16 -5
- package/dist-esm/src/credentials/managedIdentityCredential/imdsMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/index.browser.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/index.js +11 -12
- 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 +17 -5
- package/dist-esm/src/credentials/managedIdentityCredential/tokenExchangeMsi.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/utils.js +2 -10
- package/dist-esm/src/credentials/managedIdentityCredential/utils.js.map +1 -1
- package/dist-esm/src/credentials/onBehalfOfCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/usernamePasswordCredential.browser.js.map +1 -1
- package/dist-esm/src/credentials/usernamePasswordCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/visualStudioCodeCredential.js +3 -3
- package/dist-esm/src/credentials/visualStudioCodeCredential.js.map +1 -1
- package/dist-esm/src/index.js.map +1 -1
- package/dist-esm/src/msal/browserFlows/msalAuthCode.js +1 -1
- package/dist-esm/src/msal/browserFlows/msalAuthCode.js.map +1 -1
- package/dist-esm/src/msal/browserFlows/{browserCommon.js → msalBrowserCommon.js} +1 -1
- package/dist-esm/src/msal/browserFlows/msalBrowserCommon.js.map +1 -0
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +1 -1
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClientSecret.js +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js +1 -1
- package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/{nodeCommon.js → msalNodeCommon.js} +2 -2
- package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js.map +1 -0
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +1 -1
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js +1 -1
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js +1 -1
- package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js.map +1 -1
- package/dist-esm/src/plugins/consumer.js +1 -1
- package/dist-esm/src/plugins/consumer.js.map +1 -1
- package/dist-esm/src/tokenCredentialOptions.js +4 -0
- package/dist-esm/src/tokenCredentialOptions.js.map +1 -0
- package/package.json +1 -1
- package/types/identity.d.ts +4 -5
- package/dist-esm/src/msal/browserFlows/browserCommon.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/nodeCommon.js.map +0 -1
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT license.
|
|
3
|
-
import { createHttpHeaders } from "@azure/core-rest-pipeline";
|
|
3
|
+
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
4
4
|
import { credentialLogger } from "../../util/logging";
|
|
5
|
-
import { mapScopesToResource
|
|
5
|
+
import { mapScopesToResource } from "./utils";
|
|
6
6
|
const msiName = "ManagedIdentityCredential - AppServiceMSI 2017";
|
|
7
7
|
const logger = credentialLogger(msiName);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970.
|
|
10
|
+
*/
|
|
11
|
+
function expiresOnParser(requestBody) {
|
|
12
|
+
// App Service always returns string expires_on values.
|
|
11
13
|
return Date.parse(requestBody.expires_on);
|
|
12
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Generates the options used on the request for an access token.
|
|
17
|
+
*/
|
|
13
18
|
function prepareRequestOptions(scopes, clientId) {
|
|
14
19
|
const resource = mapScopesToResource(scopes);
|
|
15
20
|
if (!resource) {
|
|
@@ -39,6 +44,9 @@ function prepareRequestOptions(scopes, clientId) {
|
|
|
39
44
|
})
|
|
40
45
|
};
|
|
41
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Defines how to determine whether the Azure App Service MSI is available, and also how to retrieve a token from the Azure App Service MSI.
|
|
49
|
+
*/
|
|
42
50
|
export const appServiceMsi2017 = {
|
|
43
51
|
async isAvailable(scopes) {
|
|
44
52
|
const resource = mapScopesToResource(scopes);
|
|
@@ -56,7 +64,11 @@ export const appServiceMsi2017 = {
|
|
|
56
64
|
async getToken(configuration, getTokenOptions = {}) {
|
|
57
65
|
const { identityClient, scopes, clientId } = configuration;
|
|
58
66
|
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
|
-
|
|
67
|
+
const request = createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions(scopes, clientId)), {
|
|
68
|
+
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
|
69
|
+
allowInsecureConnection: true }));
|
|
70
|
+
const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser);
|
|
71
|
+
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
60
72
|
}
|
|
61
73
|
};
|
|
62
74
|
//# 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,
|
|
1
|
+
{"version":3,"file":"appServiceMsi2017.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/appServiceMsi2017.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 { TokenResponseParsedBody } from \"../../client/identityClient\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { mapScopesToResource } from \"./utils\";\n\nconst msiName = \"ManagedIdentityCredential - AppServiceMSI 2017\";\nconst logger = credentialLogger(msiName);\n\n/**\n * Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970.\n */\nfunction expiresOnParser(requestBody: TokenResponseParsedBody): number {\n // App Service always returns string expires_on values.\n return Date.parse(requestBody.expires_on! as string);\n}\n\n/**\n * Generates the options used on the request for an access token.\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: Record<string, string> = {\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\n/**\n * Defines how to determine whether the Azure App Service MSI is available, and also how to retrieve a token from the Azure App Service MSI.\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 const request = createPipelineRequest({\n abortSignal: getTokenOptions.abortSignal,\n ...prepareRequestOptions(scopes, clientId),\n // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).\n allowInsecureConnection: true\n });\n const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser);\n return (tokenResponse && tokenResponse.accessToken) || null;\n }\n};\n"]}
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
// Licensed under the MIT license.
|
|
3
3
|
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
4
4
|
import { readFile } from "fs";
|
|
5
|
+
import { AuthenticationError } from "../../errors";
|
|
5
6
|
import { credentialLogger } from "../../util/logging";
|
|
6
|
-
import { mapScopesToResource
|
|
7
|
+
import { mapScopesToResource } from "./utils";
|
|
7
8
|
import { azureArcAPIVersion } from "./constants";
|
|
8
|
-
import { AuthenticationError } from "../../errors";
|
|
9
9
|
const msiName = "ManagedIdentityCredential - Azure Arc MSI";
|
|
10
10
|
const logger = credentialLogger(msiName);
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Generates the options used on the request for an access token.
|
|
13
|
+
*/
|
|
13
14
|
function prepareRequestOptions(scopes) {
|
|
14
15
|
const resource = mapScopesToResource(scopes);
|
|
15
16
|
if (!resource) {
|
|
@@ -34,7 +35,10 @@ function prepareRequestOptions(scopes) {
|
|
|
34
35
|
})
|
|
35
36
|
});
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Retrieves the file contents at the given path using promises.
|
|
40
|
+
* Useful since `fs`'s readFileSync locks the thread, and to avoid extra dependencies.
|
|
41
|
+
*/
|
|
38
42
|
function readFileAsync(path, options) {
|
|
39
43
|
return new Promise((resolve, reject) => readFile(path, options, (err, data) => {
|
|
40
44
|
if (err) {
|
|
@@ -43,6 +47,9 @@ function readFileAsync(path, options) {
|
|
|
43
47
|
resolve(data);
|
|
44
48
|
}));
|
|
45
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Does a request to the authentication provider that results in a file path.
|
|
52
|
+
*/
|
|
46
53
|
async function filePathRequest(identityClient, requestPrepareOptions) {
|
|
47
54
|
const response = await identityClient.sendRequest(createPipelineRequest(requestPrepareOptions));
|
|
48
55
|
if (response.status !== 401) {
|
|
@@ -60,6 +67,9 @@ async function filePathRequest(identityClient, requestPrepareOptions) {
|
|
|
60
67
|
throw Error(`Invalid www-authenticate header format: ${authHeader}`);
|
|
61
68
|
}
|
|
62
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Defines how to determine whether the Azure Arc MSI is available, and also how to retrieve a token from the Azure Arc MSI.
|
|
72
|
+
*/
|
|
63
73
|
export const arcMsi = {
|
|
64
74
|
async isAvailable(scopes) {
|
|
65
75
|
const resource = mapScopesToResource(scopes);
|
|
@@ -87,7 +97,11 @@ export const arcMsi = {
|
|
|
87
97
|
}
|
|
88
98
|
const key = await readFileAsync(filePath, { encoding: "utf-8" });
|
|
89
99
|
(_a = requestOptions.headers) === null || _a === void 0 ? void 0 : _a.set("Authorization", `Basic ${key}`);
|
|
90
|
-
|
|
100
|
+
const request = createPipelineRequest(Object.assign(Object.assign({}, requestOptions), {
|
|
101
|
+
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
|
102
|
+
allowInsecureConnection: true }));
|
|
103
|
+
const tokenResponse = await identityClient.sendTokenRequest(request);
|
|
104
|
+
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
91
105
|
}
|
|
92
106
|
};
|
|
93
107
|
//# sourceMappingURL=arcMsi.js.map
|
|
@@ -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;
|
|
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 { AuthenticationError } from \"../../errors\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { IdentityClient } from \"../../client/identityClient\";\nimport { mapScopesToResource } from \"./utils\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { azureArcAPIVersion } from \"./constants\";\n\nconst msiName = \"ManagedIdentityCredential - Azure Arc MSI\";\nconst logger = credentialLogger(msiName);\n\n/**\n * Generates the options used on the request for an access token.\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: Record<string, string> = {\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/**\n * Retrieves the file contents at the given path using promises.\n * Useful since `fs`'s readFileSync locks the thread, and to avoid extra dependencies.\n */\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\n/**\n * Does a request to the authentication provider that results in a file path.\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\n/**\n * Defines how to determine whether the Azure Arc MSI is available, and also how to retrieve a token from the Azure Arc MSI.\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 const request = createPipelineRequest({\n ...requestOptions,\n // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).\n allowInsecureConnection: true\n });\n const tokenResponse = await identityClient.sendTokenRequest(request);\n return (tokenResponse && tokenResponse.accessToken) || null;\n }\n};\n"]}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT license.
|
|
3
|
-
import { createHttpHeaders } from "@azure/core-rest-pipeline";
|
|
3
|
+
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
4
4
|
import { credentialLogger } from "../../util/logging";
|
|
5
|
-
import { mapScopesToResource
|
|
5
|
+
import { mapScopesToResource } from "./utils";
|
|
6
6
|
const msiName = "ManagedIdentityCredential - CloudShellMSI";
|
|
7
7
|
const logger = credentialLogger(msiName);
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Generates the options used on the request for an access token.
|
|
10
|
+
*/
|
|
10
11
|
function prepareRequestOptions(scopes, clientId) {
|
|
11
12
|
const resource = mapScopesToResource(scopes);
|
|
12
13
|
if (!resource) {
|
|
@@ -34,6 +35,9 @@ function prepareRequestOptions(scopes, clientId) {
|
|
|
34
35
|
})
|
|
35
36
|
};
|
|
36
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Defines how to determine whether the Azure Cloud Shell MSI is available, and also how to retrieve a token from the Azure Cloud Shell MSI.
|
|
40
|
+
*/
|
|
37
41
|
export const cloudShellMsi = {
|
|
38
42
|
async isAvailable(scopes) {
|
|
39
43
|
const resource = mapScopesToResource(scopes);
|
|
@@ -50,7 +54,11 @@ export const cloudShellMsi = {
|
|
|
50
54
|
async getToken(configuration, getTokenOptions = {}) {
|
|
51
55
|
const { identityClient, scopes, clientId } = configuration;
|
|
52
56
|
logger.info(`${msiName}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.`);
|
|
53
|
-
|
|
57
|
+
const request = createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions(scopes, clientId)), {
|
|
58
|
+
// Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).
|
|
59
|
+
allowInsecureConnection: true }));
|
|
60
|
+
const tokenResponse = await identityClient.sendTokenRequest(request);
|
|
61
|
+
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
54
62
|
}
|
|
55
63
|
};
|
|
56
64
|
//# 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,
|
|
1
|
+
{"version":3,"file":"cloudShellMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/cloudShellMsi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,OAAO,GAAG,2CAA2C,CAAC;AAC5D,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAEzC;;GAEG;AACH,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,GAA2B;QACnC,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;;GAEG;AACH,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,MAAM,OAAO,GAAG,qBAAqB,+BACnC,WAAW,EAAE,eAAe,CAAC,WAAW,IACrC,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC;YAC1C,0FAA0F;YAC1F,uBAAuB,EAAE,IAAI,IAC7B,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACrE,OAAO,CAAC,aAAa,IAAI,aAAa,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC;IAC9D,CAAC;CACF,CAAC","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 { credentialLogger } from \"../../util/logging\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { mapScopesToResource } from \"./utils\";\n\nconst msiName = \"ManagedIdentityCredential - CloudShellMSI\";\nconst logger = credentialLogger(msiName);\n\n/**\n * Generates the options used on the request for an access token.\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: Record<string, string> = {\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\n/**\n * Defines how to determine whether the Azure Cloud Shell MSI is available, and also how to retrieve a token from the Azure Cloud Shell MSI.\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 const request = createPipelineRequest({\n abortSignal: getTokenOptions.abortSignal,\n ...prepareRequestOptions(scopes, clientId),\n // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS).\n allowInsecureConnection: true\n });\n const tokenResponse = await identityClient.sendTokenRequest(request);\n return (tokenResponse && tokenResponse.accessToken) || null;\n }\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/constants.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/constants.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAC;AAC9C,MAAM,CAAC,MAAM,QAAQ,GAAG,wBAAwB,CAAC;AACjD,MAAM,CAAC,MAAM,gBAAgB,GAAG,iCAAiC,CAAC;AAClE,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAC3C,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nexport const DefaultScopeSuffix = \"/.default\";\nexport const imdsHost = \"http://169.254.169.254\";\nexport const imdsEndpointPath = \"/metadata/identity/oauth2/token\";\nexport const imdsApiVersion = \"2018-02-01\";\nexport const azureArcAPIVersion = \"2019-11-01\";\nexport const azureFabricVersion = \"2019-07-01-preview\";\n"]}
|
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT license.
|
|
3
3
|
import https from "https";
|
|
4
|
-
import { createHttpHeaders } from "@azure/core-rest-pipeline";
|
|
4
|
+
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
5
5
|
import { credentialLogger } from "../../util/logging";
|
|
6
|
-
import { mapScopesToResource
|
|
6
|
+
import { mapScopesToResource } from "./utils";
|
|
7
7
|
import { azureFabricVersion } from "./constants";
|
|
8
|
+
// This MSI can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile:
|
|
9
|
+
//
|
|
10
|
+
// FROM node:12
|
|
11
|
+
// RUN wget https://host.any/path/bash.sh
|
|
12
|
+
// CMD ["bash", "bash.sh"]
|
|
13
|
+
//
|
|
14
|
+
// Where the bash script contains:
|
|
15
|
+
//
|
|
16
|
+
// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER"
|
|
17
|
+
//
|
|
8
18
|
const msiName = "ManagedIdentityCredential - Fabric MSI";
|
|
9
19
|
const logger = credentialLogger(msiName);
|
|
10
|
-
|
|
11
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970.
|
|
22
|
+
*/
|
|
23
|
+
function expiresOnParser(requestBody) {
|
|
24
|
+
// Parses a string representation of the milliseconds since epoch into a number value
|
|
12
25
|
return Number(requestBody.expires_on);
|
|
13
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Generates the options used on the request for an access token.
|
|
29
|
+
*/
|
|
14
30
|
function prepareRequestOptions(scopes, clientId) {
|
|
15
31
|
const resource = mapScopesToResource(scopes);
|
|
16
32
|
if (!resource) {
|
|
@@ -40,16 +56,9 @@ function prepareRequestOptions(scopes, clientId) {
|
|
|
40
56
|
})
|
|
41
57
|
};
|
|
42
58
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// RUN wget https://host.any/path/bash.sh
|
|
47
|
-
// CMD ["bash", "bash.sh"]
|
|
48
|
-
//
|
|
49
|
-
// Where the bash script contains:
|
|
50
|
-
//
|
|
51
|
-
// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER"
|
|
52
|
-
//
|
|
59
|
+
/**
|
|
60
|
+
* Defines how to determine whether the Azure Service Fabric MSI is available, and also how to retrieve a token from the Azure Service Fabric MSI.
|
|
61
|
+
*/
|
|
53
62
|
export const fabricMsi = {
|
|
54
63
|
async isAvailable(scopes) {
|
|
55
64
|
const resource = mapScopesToResource(scopes);
|
|
@@ -73,11 +82,17 @@ export const fabricMsi = {
|
|
|
73
82
|
"IDENTITY_HEADER=[REDACTED] and",
|
|
74
83
|
"IDENTITY_SERVER_THUMBPRINT=[REDACTED]."
|
|
75
84
|
].join(" "));
|
|
76
|
-
|
|
85
|
+
const request = createPipelineRequest(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions(scopes, clientId)
|
|
86
|
+
// The service fabric MSI endpoint will be HTTPS (however, the certificate will be self-signed).
|
|
87
|
+
// allowInsecureConnection: true
|
|
88
|
+
));
|
|
89
|
+
request.agent = new https.Agent({
|
|
77
90
|
// This is necessary because Service Fabric provides a self-signed certificate.
|
|
78
91
|
// The alternative path is to verify the certificate using the IDENTITY_SERVER_THUMBPRINT env variable.
|
|
79
92
|
rejectUnauthorized: false
|
|
80
|
-
})
|
|
93
|
+
});
|
|
94
|
+
const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser);
|
|
95
|
+
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
81
96
|
}
|
|
82
97
|
};
|
|
83
98
|
//# 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,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,
|
|
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 https from \"https\";\nimport {\n createHttpHeaders,\n createPipelineRequest,\n PipelineRequestOptions\n} from \"@azure/core-rest-pipeline\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport { TokenResponseParsedBody } from \"../../client/identityClient\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { mapScopesToResource } from \"./utils\";\nimport { azureFabricVersion } from \"./constants\";\n\n// This MSI 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\nconst msiName = \"ManagedIdentityCredential - Fabric MSI\";\nconst logger = credentialLogger(msiName);\n\n/**\n * Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970.\n */\nfunction expiresOnParser(requestBody: TokenResponseParsedBody): number {\n // Parses a string representation of the milliseconds since epoch into a number value\n return Number(requestBody.expires_on);\n}\n\n/**\n * Generates the options used on the request for an access token.\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: Record<string, string> = {\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/**\n * Defines how to determine whether the Azure Service Fabric MSI is available, and also how to retrieve a token from the Azure Service Fabric MSI.\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 { scopes, identityClient, 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 const request = createPipelineRequest({\n abortSignal: getTokenOptions.abortSignal,\n ...prepareRequestOptions(scopes, clientId)\n // The service fabric MSI endpoint will be HTTPS (however, the certificate will be self-signed).\n // allowInsecureConnection: true\n });\n\n request.agent = new https.Agent({\n // This is necessary because Service Fabric provides a self-signed certificate.\n // The alternative path is to verify the certificate using the IDENTITY_SERVER_THUMBPRINT env variable.\n rejectUnauthorized: false\n });\n\n const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser);\n return (tokenResponse && tokenResponse.accessToken) || null;\n }\n};\n"]}
|
|
@@ -4,13 +4,16 @@ import { delay } from "@azure/core-util";
|
|
|
4
4
|
import { createHttpHeaders, createPipelineRequest, RestError } from "@azure/core-rest-pipeline";
|
|
5
5
|
import { SpanStatusCode } from "@azure/core-tracing";
|
|
6
6
|
import { credentialLogger } from "../../util/logging";
|
|
7
|
+
import { AuthenticationError } from "../../errors";
|
|
7
8
|
import { createSpan } from "../../util/tracing";
|
|
8
9
|
import { imdsApiVersion, imdsEndpointPath, imdsHost } from "./constants";
|
|
9
|
-
import { mapScopesToResource
|
|
10
|
-
import { AuthenticationError } from "../../errors";
|
|
10
|
+
import { mapScopesToResource } from "./utils";
|
|
11
11
|
const msiName = "ManagedIdentityCredential - IMDS";
|
|
12
12
|
const logger = credentialLogger(msiName);
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970.
|
|
15
|
+
*/
|
|
16
|
+
function expiresOnParser(requestBody) {
|
|
14
17
|
if (requestBody.expires_on) {
|
|
15
18
|
// Use the expires_on timestamp if it's available
|
|
16
19
|
const expires = +requestBody.expires_on * 1000;
|
|
@@ -24,6 +27,9 @@ function expiresInParser(requestBody) {
|
|
|
24
27
|
return expires;
|
|
25
28
|
}
|
|
26
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Generates the options used on the request for an access token.
|
|
32
|
+
*/
|
|
27
33
|
function prepareRequestOptions(scopes, clientId, options) {
|
|
28
34
|
var _a;
|
|
29
35
|
const resource = mapScopesToResource(scopes);
|
|
@@ -67,6 +73,9 @@ export const imdsMsiRetryConfig = {
|
|
|
67
73
|
startDelayInMs: 800,
|
|
68
74
|
intervalIncrement: 2
|
|
69
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Defines how to determine whether the Azure IMDS MSI is available, and also how to retrieve a token from the Azure IMDS MSI.
|
|
78
|
+
*/
|
|
70
79
|
export const imdsMsi = {
|
|
71
80
|
async isAvailable(scopes, identityClient, clientId, getTokenOptions) {
|
|
72
81
|
var _a, _b;
|
|
@@ -76,7 +85,7 @@ export const imdsMsi = {
|
|
|
76
85
|
return false;
|
|
77
86
|
}
|
|
78
87
|
const { span, updatedOptions: options } = createSpan("ManagedIdentityCredential-pingImdsEndpoint", getTokenOptions);
|
|
79
|
-
// if the
|
|
88
|
+
// if the PodIdentityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist
|
|
80
89
|
if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {
|
|
81
90
|
return true;
|
|
82
91
|
}
|
|
@@ -138,7 +147,9 @@ export const imdsMsi = {
|
|
|
138
147
|
let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;
|
|
139
148
|
for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {
|
|
140
149
|
try {
|
|
141
|
-
|
|
150
|
+
const request = createPipelineRequest(Object.assign(Object.assign({ abortSignal: getTokenOptions.abortSignal }, prepareRequestOptions(scopes, clientId)), { allowInsecureConnection: true }));
|
|
151
|
+
const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser);
|
|
152
|
+
return (tokenResponse && tokenResponse.accessToken) || null;
|
|
142
153
|
}
|
|
143
154
|
catch (error) {
|
|
144
155
|
if (error.statusCode === 404) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imdsMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/imdsMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { delay } from \"@azure/core-util\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport {\n createHttpHeaders,\n PipelineRequestOptions,\n createPipelineRequest,\n RestError\n} from \"@azure/core-rest-pipeline\";\nimport { SpanStatusCode } from \"@azure/core-tracing\";\nimport { IdentityClient } from \"../../client/identityClient\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { createSpan } from \"../../util/tracing\";\nimport { imdsApiVersion, imdsEndpointPath, imdsHost } from \"./constants\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { mapScopesToResource, msiGenericGetToken } from \"./utils\";\nimport { AuthenticationError } from \"../../errors\";\n\nconst msiName = \"ManagedIdentityCredential - IMDS\";\nconst logger = credentialLogger(msiName);\n\nfunction expiresInParser(requestBody: any): number {\n if (requestBody.expires_on) {\n // Use the expires_on timestamp if it's available\n const expires = +requestBody.expires_on * 1000;\n logger.info(\n `${msiName}: Using expires_on: ${expires} (original value: ${requestBody.expires_on})`\n );\n return expires;\n } else {\n // If these aren't possible, use expires_in and calculate a timestamp\n const expires = Date.now() + requestBody.expires_in * 1000;\n logger.info(\n `${msiName}: IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`\n );\n return expires;\n }\n}\n\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientId?: string,\n options?: {\n skipQuery?: boolean;\n skipMetadataHeader?: boolean;\n }\n): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n\n const { skipQuery, skipMetadataHeader } = options || {};\n let query = \"\";\n\n // Pod Identity will try to process this request even if the Metadata header is missing.\n // We can exclude the request query to ensure no IMDS endpoint tries to process the ping request.\n if (!skipQuery) {\n const queryParameters: any = {\n resource,\n \"api-version\": imdsApiVersion\n };\n if (clientId) {\n queryParameters.client_id = clientId;\n }\n const params = new URLSearchParams(queryParameters);\n query = `?${params.toString()}`;\n }\n\n const url = new URL(imdsEndpointPath, process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST ?? imdsHost);\n\n const rawHeaders: Record<string, string> = {\n Accept: \"application/json\",\n Metadata: \"true\"\n };\n\n // Remove the Metadata header to invoke a request error from some IMDS endpoints.\n if (skipMetadataHeader) {\n delete rawHeaders.Metadata;\n }\n\n return {\n // In this case, the `?` should be added in the \"query\" variable `skipQuery` is not set.\n url: `${url}${query}`,\n method: \"GET\",\n headers: createHttpHeaders(rawHeaders)\n };\n}\n\n// 800ms -> 1600ms -> 3200ms\nexport const imdsMsiRetryConfig = {\n maxRetries: 3,\n startDelayInMs: 800,\n intervalIncrement: 2\n};\n\nexport const imdsMsi: MSI = {\n async isAvailable(\n scopes: string | string[],\n identityClient: IdentityClient,\n clientId?: string,\n getTokenOptions?: GetTokenOptions\n ): 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 { span, updatedOptions: options } = createSpan(\n \"ManagedIdentityCredential-pingImdsEndpoint\",\n getTokenOptions\n );\n\n // if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist\n if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {\n return true;\n }\n\n const requestOptions = prepareRequestOptions(resource, clientId, {\n skipMetadataHeader: true,\n skipQuery: true\n });\n requestOptions.tracingOptions = options.tracingOptions;\n\n try {\n // Create a request with a timeout since we expect that\n // not having a \"Metadata\" header should cause an error to be\n // returned quickly from the endpoint, proving its availability.\n const request = createPipelineRequest(requestOptions);\n\n request.timeout = options.requestOptions?.timeout ?? 300;\n\n // This MSI uses the imdsEndpoint to get the token, which only uses http://\n request.allowInsecureConnection = true;\n\n try {\n logger.info(`${msiName}: Pinging the Azure IMDS endpoint`);\n await identityClient.sendRequest(request);\n } catch (err) {\n if (\n (err.name === \"RestError\" && err.code === RestError.REQUEST_SEND_ERROR) ||\n err.name === \"AbortError\" ||\n err.code === \"ENETUNREACH\" || // Network unreachable\n err.code === \"ECONNREFUSED\" || // connection refused\n err.code === \"EHOSTDOWN\" // host is down\n ) {\n // If the request failed, or Node.js was unable to establish a connection,\n // or the host was down, we'll assume the IMDS endpoint isn't available.\n logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: err.message\n });\n return false;\n }\n }\n\n // If we received any response, the endpoint is available\n logger.info(`${msiName}: The Azure IMDS endpoint is available`);\n return true;\n } catch (err) {\n // createWebResource failed.\n // This error should bubble up to the user.\n logger.info(\n `${msiName}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`\n );\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: err.message\n });\n throw err;\n } finally {\n span.end();\n }\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 Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`\n );\n\n let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;\n for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {\n try {\n return await msiGenericGetToken(\n identityClient,\n prepareRequestOptions(scopes, clientId),\n expiresInParser,\n getTokenOptions\n );\n } catch (error) {\n if (error.statusCode === 404) {\n await delay(nextDelayInMs);\n nextDelayInMs *= imdsMsiRetryConfig.intervalIncrement;\n continue;\n }\n throw error;\n }\n }\n\n throw new AuthenticationError(\n 404,\n `${msiName}: Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`\n );\n }\n};\n"]}
|
|
1
|
+
{"version":3,"file":"imdsMsi.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/imdsMsi.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { delay } from \"@azure/core-util\";\nimport { AccessToken, GetTokenOptions } from \"@azure/core-auth\";\nimport {\n createHttpHeaders,\n createPipelineRequest,\n PipelineRequestOptions,\n RestError\n} from \"@azure/core-rest-pipeline\";\nimport { SpanStatusCode } from \"@azure/core-tracing\";\nimport { IdentityClient, TokenResponseParsedBody } from \"../../client/identityClient\";\nimport { credentialLogger } from \"../../util/logging\";\nimport { AuthenticationError } from \"../../errors\";\nimport { createSpan } from \"../../util/tracing\";\nimport { imdsApiVersion, imdsEndpointPath, imdsHost } from \"./constants\";\nimport { MSI, MSIConfiguration } from \"./models\";\nimport { mapScopesToResource } from \"./utils\";\n\nconst msiName = \"ManagedIdentityCredential - IMDS\";\nconst logger = credentialLogger(msiName);\n\n/**\n * Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970.\n */\nfunction expiresOnParser(requestBody: TokenResponseParsedBody): number {\n if (requestBody.expires_on) {\n // Use the expires_on timestamp if it's available\n const expires = +requestBody.expires_on * 1000;\n logger.info(\n `${msiName}: Using expires_on: ${expires} (original value: ${requestBody.expires_on})`\n );\n return expires;\n } else {\n // If these aren't possible, use expires_in and calculate a timestamp\n const expires = Date.now() + requestBody.expires_in * 1000;\n logger.info(\n `${msiName}: IMDS using expires_in: ${expires} (original value: ${requestBody.expires_in})`\n );\n return expires;\n }\n}\n\n/**\n * Generates the options used on the request for an access token.\n */\nfunction prepareRequestOptions(\n scopes: string | string[],\n clientId?: string,\n options?: {\n skipQuery?: boolean;\n skipMetadataHeader?: boolean;\n }\n): PipelineRequestOptions {\n const resource = mapScopesToResource(scopes);\n if (!resource) {\n throw new Error(`${msiName}: Multiple scopes are not supported.`);\n }\n\n const { skipQuery, skipMetadataHeader } = options || {};\n let query = \"\";\n\n // Pod Identity will try to process this request even if the Metadata header is missing.\n // We can exclude the request query to ensure no IMDS endpoint tries to process the ping request.\n if (!skipQuery) {\n const queryParameters: Record<string, string> = {\n resource,\n \"api-version\": imdsApiVersion\n };\n if (clientId) {\n queryParameters.client_id = clientId;\n }\n const params = new URLSearchParams(queryParameters);\n query = `?${params.toString()}`;\n }\n\n const url = new URL(imdsEndpointPath, process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST ?? imdsHost);\n\n const rawHeaders: Record<string, string> = {\n Accept: \"application/json\",\n Metadata: \"true\"\n };\n\n // Remove the Metadata header to invoke a request error from some IMDS endpoints.\n if (skipMetadataHeader) {\n delete rawHeaders.Metadata;\n }\n\n return {\n // In this case, the `?` should be added in the \"query\" variable `skipQuery` is not set.\n url: `${url}${query}`,\n method: \"GET\",\n headers: createHttpHeaders(rawHeaders)\n };\n}\n\n// 800ms -> 1600ms -> 3200ms\nexport const imdsMsiRetryConfig = {\n maxRetries: 3,\n startDelayInMs: 800,\n intervalIncrement: 2\n};\n\n/**\n * Defines how to determine whether the Azure IMDS MSI is available, and also how to retrieve a token from the Azure IMDS MSI.\n */\nexport const imdsMsi: MSI = {\n async isAvailable(\n scopes: string | string[],\n identityClient: IdentityClient,\n clientId?: string,\n getTokenOptions?: GetTokenOptions\n ): 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 { span, updatedOptions: options } = createSpan(\n \"ManagedIdentityCredential-pingImdsEndpoint\",\n getTokenOptions\n );\n\n // if the PodIdentityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist\n if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) {\n return true;\n }\n\n const requestOptions = prepareRequestOptions(resource, clientId, {\n skipMetadataHeader: true,\n skipQuery: true\n });\n requestOptions.tracingOptions = options.tracingOptions;\n\n try {\n // Create a request with a timeout since we expect that\n // not having a \"Metadata\" header should cause an error to be\n // returned quickly from the endpoint, proving its availability.\n const request = createPipelineRequest(requestOptions);\n\n request.timeout = options.requestOptions?.timeout ?? 300;\n\n // This MSI uses the imdsEndpoint to get the token, which only uses http://\n request.allowInsecureConnection = true;\n\n try {\n logger.info(`${msiName}: Pinging the Azure IMDS endpoint`);\n await identityClient.sendRequest(request);\n } catch (err) {\n if (\n (err.name === \"RestError\" && err.code === RestError.REQUEST_SEND_ERROR) ||\n err.name === \"AbortError\" ||\n err.code === \"ENETUNREACH\" || // Network unreachable\n err.code === \"ECONNREFUSED\" || // connection refused\n err.code === \"EHOSTDOWN\" // host is down\n ) {\n // If the request failed, or Node.js was unable to establish a connection,\n // or the host was down, we'll assume the IMDS endpoint isn't available.\n logger.info(`${msiName}: The Azure IMDS endpoint is unavailable`);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: err.message\n });\n return false;\n }\n }\n\n // If we received any response, the endpoint is available\n logger.info(`${msiName}: The Azure IMDS endpoint is available`);\n return true;\n } catch (err) {\n // createWebResource failed.\n // This error should bubble up to the user.\n logger.info(\n `${msiName}: Error when creating the WebResource for the Azure IMDS endpoint: ${err.message}`\n );\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: err.message\n });\n throw err;\n } finally {\n span.end();\n }\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 Azure IMDS endpoint coming from the environment variable MSI_ENDPOINT=${process.env.MSI_ENDPOINT}, and using the cloud shell to proceed with the authentication.`\n );\n\n let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs;\n for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) {\n try {\n const request = createPipelineRequest({\n abortSignal: getTokenOptions.abortSignal,\n ...prepareRequestOptions(scopes, clientId),\n allowInsecureConnection: true\n });\n const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser);\n return (tokenResponse && tokenResponse.accessToken) || null;\n } catch (error) {\n if (error.statusCode === 404) {\n await delay(nextDelayInMs);\n nextDelayInMs *= imdsMsiRetryConfig.intervalIncrement;\n continue;\n }\n throw error;\n }\n }\n\n throw new AuthenticationError(\n 404,\n `${msiName}: Failed to retrieve IMDS token after ${imdsMsiRetryConfig.maxRetries} retries.`\n );\n }\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/index.browser.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAKlC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEnE,MAAM,wBAAwB,GAAG,IAAI,KAAK,CACxC,4DAA4D,CAC7D,CAAC;AACF,MAAM,MAAM,GAAG,gBAAgB,CAAC,2BAA2B,CAAC,CAAC;AAE7D,MAAM,OAAO,yBAAyB;IAGpC;QACE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;QACvD,MAAM,wBAAwB,CAAC;IACjC,CAAC;IAEM,KAAK,CAAC,QAAQ;QACnB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;QAChE,MAAM,wBAAwB,CAAC;IACjC,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken, TokenCredential } from \"@azure/core-auth\";\n\nimport { TokenCredentialOptions } from \"../../
|
|
1
|
+
{"version":3,"file":"index.browser.js","sourceRoot":"","sources":["../../../../src/credentials/managedIdentityCredential/index.browser.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAKlC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEnE,MAAM,wBAAwB,GAAG,IAAI,KAAK,CACxC,4DAA4D,CAC7D,CAAC;AACF,MAAM,MAAM,GAAG,gBAAgB,CAAC,2BAA2B,CAAC,CAAC;AAE7D,MAAM,OAAO,yBAAyB;IAGpC;QACE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;QACvD,MAAM,wBAAwB,CAAC;IACjC,CAAC;IAEM,KAAK,CAAC,QAAQ;QACnB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;QAChE,MAAM,wBAAwB,CAAC;IACjC,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken, TokenCredential } from \"@azure/core-auth\";\n\nimport { TokenCredentialOptions } from \"../../tokenCredentialOptions\";\nimport { credentialLogger, formatError } from \"../../util/logging\";\n\nconst BrowserNotSupportedError = new Error(\n \"ManagedIdentityCredential is not supported in the browser.\"\n);\nconst logger = credentialLogger(\"ManagedIdentityCredential\");\n\nexport class ManagedIdentityCredential implements TokenCredential {\n constructor(clientId: string, options?: TokenCredentialOptions);\n constructor(options?: TokenCredentialOptions);\n constructor() {\n logger.info(formatError(\"\", BrowserNotSupportedError));\n throw BrowserNotSupportedError;\n }\n\n public async getToken(): Promise<AccessToken | null> {\n logger.getToken.info(formatError(\"\", BrowserNotSupportedError));\n throw BrowserNotSupportedError;\n }\n}\n"]}
|
|
@@ -13,12 +13,11 @@ import { tokenExchangeMsi } from "./tokenExchangeMsi";
|
|
|
13
13
|
import { fabricMsi } from "./fabricMsi";
|
|
14
14
|
const logger = credentialLogger("ManagedIdentityCredential");
|
|
15
15
|
/**
|
|
16
|
-
* Attempts authentication using a managed identity
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Attempts authentication using a managed identity available at the deployment environment.
|
|
17
|
+
* This authentication type works in Azure VMs, App Service instances, Azure Functions applications,
|
|
18
|
+
* Azure Kubernetes Services, Azure Service Fabric instances and inside of the Azure Cloud Shell.
|
|
19
19
|
*
|
|
20
20
|
* More information about configuring managed identities can be found here:
|
|
21
|
-
*
|
|
22
21
|
* https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
|
|
23
22
|
*/
|
|
24
23
|
export class ManagedIdentityCredential {
|
|
@@ -49,10 +48,10 @@ export class ManagedIdentityCredential {
|
|
|
49
48
|
return msi;
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
|
-
throw new CredentialUnavailableError(
|
|
51
|
+
throw new CredentialUnavailableError(`${ManagedIdentityCredential.name} - No MSI credential available`);
|
|
53
52
|
}
|
|
54
53
|
async authenticateManagedIdentity(scopes, clientId, getTokenOptions) {
|
|
55
|
-
const { span, updatedOptions } = createSpan(
|
|
54
|
+
const { span, updatedOptions } = createSpan(`${ManagedIdentityCredential.name}.authenticateManagedIdentity`, getTokenOptions);
|
|
56
55
|
try {
|
|
57
56
|
// Determining the available MSI, and avoiding checking for other MSIs while the program is running.
|
|
58
57
|
const availableMSI = await this.cachedAvailableMSI(scopes, clientId, updatedOptions);
|
|
@@ -84,7 +83,7 @@ export class ManagedIdentityCredential {
|
|
|
84
83
|
*/
|
|
85
84
|
async getToken(scopes, options) {
|
|
86
85
|
let result = null;
|
|
87
|
-
const { span, updatedOptions } = createSpan(
|
|
86
|
+
const { span, updatedOptions } = createSpan(`${ManagedIdentityCredential.name}.getToken`, options);
|
|
88
87
|
try {
|
|
89
88
|
// isEndpointAvailable can be true, false, or null,
|
|
90
89
|
// If it's null, it means we don't yet know whether
|
|
@@ -135,30 +134,30 @@ export class ManagedIdentityCredential {
|
|
|
135
134
|
// If either the network is unreachable,
|
|
136
135
|
// we can safely assume the credential is unavailable.
|
|
137
136
|
if (err.code === "ENETUNREACH") {
|
|
138
|
-
const error = new CredentialUnavailableError(
|
|
137
|
+
const error = new CredentialUnavailableError(`${ManagedIdentityCredential.name}: Unavailable. Network unreachable. Message: ${err.message}`);
|
|
139
138
|
logger.getToken.info(formatError(scopes, error));
|
|
140
139
|
throw error;
|
|
141
140
|
}
|
|
142
141
|
// If either the host was unreachable,
|
|
143
142
|
// we can safely assume the credential is unavailable.
|
|
144
143
|
if (err.code === "EHOSTUNREACH") {
|
|
145
|
-
const error = new CredentialUnavailableError(
|
|
144
|
+
const error = new CredentialUnavailableError(`${ManagedIdentityCredential.name}: Unavailable. No managed identity endpoint found. Message: ${err.message}`);
|
|
146
145
|
logger.getToken.info(formatError(scopes, error));
|
|
147
146
|
throw error;
|
|
148
147
|
}
|
|
149
148
|
// If err.statusCode has a value of 400, it comes from sendTokenRequest,
|
|
150
149
|
// and it means that the endpoint is working, but that no identity is available.
|
|
151
150
|
if (err.statusCode === 400) {
|
|
152
|
-
throw new CredentialUnavailableError(
|
|
151
|
+
throw new CredentialUnavailableError(`${ManagedIdentityCredential.name}: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}`);
|
|
153
152
|
}
|
|
154
153
|
// If the error has no status code, we can assume there was no available identity.
|
|
155
154
|
// This will throw silently during any ChainedTokenCredential.
|
|
156
155
|
if (err.statusCode === undefined) {
|
|
157
|
-
throw new CredentialUnavailableError(
|
|
156
|
+
throw new CredentialUnavailableError(`${ManagedIdentityCredential.name}: Authentication failed. Message ${err.message}`);
|
|
158
157
|
}
|
|
159
158
|
// Any other error should break the chain.
|
|
160
159
|
throw new AuthenticationError(err.statusCode, {
|
|
161
|
-
error:
|
|
160
|
+
error: `${ManagedIdentityCredential.name} authentication failed.`,
|
|
162
161
|
error_description: err.message
|
|
163
162
|
});
|
|
164
163
|
}
|