@azure/identity 4.5.0-beta.1 → 4.5.0-beta.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +22 -1
- package/dist/index.js +238 -112
- package/dist/index.js.map +1 -1
- package/dist-esm/src/client/identityClient.js +1 -2
- package/dist-esm/src/client/identityClient.js.map +1 -1
- package/dist-esm/src/constants.js +1 -1
- package/dist-esm/src/constants.js.map +1 -1
- package/dist-esm/src/credentials/azurePipelinesCredential.js +50 -26
- package/dist-esm/src/credentials/azurePipelinesCredential.js.map +1 -1
- package/dist-esm/src/credentials/azurePowerShellCredential.js +63 -19
- package/dist-esm/src/credentials/azurePowerShellCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientAssertionCredential.js +9 -2
- package/dist-esm/src/credentials/clientAssertionCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientCertificateCredential.js +35 -27
- package/dist-esm/src/credentials/clientCertificateCredential.js.map +1 -1
- package/dist-esm/src/credentials/clientSecretCredential.js +9 -2
- package/dist-esm/src/credentials/clientSecretCredential.js.map +1 -1
- package/dist-esm/src/credentials/deviceCodeCredential.js +1 -1
- package/dist-esm/src/credentials/deviceCodeCredential.js.map +1 -1
- package/dist-esm/src/credentials/deviceCodeCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/environmentCredential.js +11 -1
- 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/interactiveBrowserCredential.js +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredential.js.map +1 -1
- package/dist-esm/src/credentials/interactiveBrowserCredentialOptions.js.map +1 -1
- package/dist-esm/src/credentials/managedIdentityCredential/msalMsiProvider.js +6 -5
- package/dist-esm/src/credentials/managedIdentityCredential/msalMsiProvider.js.map +1 -1
- package/dist-esm/src/credentials/onBehalfOfCredential.js +16 -9
- package/dist-esm/src/credentials/onBehalfOfCredential.js.map +1 -1
- package/dist-esm/src/credentials/usernamePasswordCredential.js +13 -3
- package/dist-esm/src/credentials/usernamePasswordCredential.js.map +1 -1
- package/dist-esm/src/credentials/workloadIdentityCredential.js +16 -6
- package/dist-esm/src/credentials/workloadIdentityCredential.js.map +1 -1
- package/dist-esm/src/errors.js +12 -7
- package/dist-esm/src/errors.js.map +1 -1
- package/dist-esm/src/msal/browserFlows/flows.js.map +1 -0
- package/dist-esm/src/msal/browserFlows/msalBrowserCommon.js.map +1 -1
- package/dist-esm/src/msal/nodeFlows/msalClient.js +8 -1
- package/dist-esm/src/msal/nodeFlows/msalClient.js.map +1 -1
- package/package.json +3 -3
- package/types/identity.d.ts +26 -8
- package/dist-esm/src/msal/flows.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js +0 -47
- package/dist-esm/src/msal/nodeFlows/msalAuthorizationCode.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalClientAssertion.js +0 -42
- package/dist-esm/src/msal/nodeFlows/msalClientAssertion.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js +0 -112
- package/dist-esm/src/msal/nodeFlows/msalClientCertificate.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalClientSecret.js +0 -33
- package/dist-esm/src/msal/nodeFlows/msalClientSecret.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js +0 -35
- package/dist-esm/src/msal/nodeFlows/msalDeviceCode.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js +0 -323
- package/dist-esm/src/msal/nodeFlows/msalNodeCommon.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js +0 -58
- package/dist-esm/src/msal/nodeFlows/msalOnBehalfOf.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js +0 -113
- package/dist-esm/src/msal/nodeFlows/msalOpenBrowser.js.map +0 -1
- package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js +0 -33
- package/dist-esm/src/msal/nodeFlows/msalUsernamePassword.js.map +0 -1
- /package/dist-esm/src/msal/{flows.js → browserFlows/flows.js} +0 -0
package/README.md
CHANGED
@@ -213,7 +213,7 @@ For examples of how to use managed identity for authentication, see [the example
|
|
213
213
|
|
214
214
|
## Cloud configuration
|
215
215
|
|
216
|
-
Credentials default to authenticating to the Microsoft Entra endpoint for Azure Public Cloud. To access resources in other clouds, such as Azure Government or a private cloud, configure credentials with the `authorityHost` argument in the constructor. The `AzureAuthorityHosts`
|
216
|
+
Credentials default to authenticating to the Microsoft Entra endpoint for Azure Public Cloud. To access resources in other clouds, such as Azure Government or a private cloud, configure credentials with the `authorityHost` argument in the constructor. The [`AzureAuthorityHosts`][authority_hosts] enum defines authorities for well-known clouds. For the US Government cloud, you could instantiate a credential this way:
|
217
217
|
|
218
218
|
```typescript
|
219
219
|
import { AzureAuthorityHosts, ClientSecretCredential } from "@azure/identity";
|
@@ -227,6 +227,26 @@ const credential = new ClientSecretCredential(
|
|
227
227
|
);
|
228
228
|
```
|
229
229
|
|
230
|
+
As an alternative to specifying the `authorityHost` argument, you can also set the `AZURE_AUTHORITY_HOST` environment variable to the URL of your cloud's authority. This approach is useful when configuring multiple credentials to authenticate to the same cloud or when the deployed environment needs to define the target cloud:
|
231
|
+
|
232
|
+
```sh
|
233
|
+
AZURE_AUTHORITY_HOST=https://login.partner.microsoftonline.cn
|
234
|
+
```
|
235
|
+
|
236
|
+
The `AzureAuthorityHosts` enum defines authorities for well-known clouds for your convenience; however, if the authority for your cloud isn't listed in `AzureAuthorityHosts`, you may pass any valid authority URL as a string argument. For example:
|
237
|
+
|
238
|
+
```typescript
|
239
|
+
import { AzureAuthorityHosts, ClientSecretCredential } from "@azure/identity";
|
240
|
+
const credential = new ClientSecretCredential(
|
241
|
+
"<YOUR_TENANT_ID>",
|
242
|
+
"<YOUR_CLIENT_ID>",
|
243
|
+
"<YOUR_CLIENT_SECRET>",
|
244
|
+
{
|
245
|
+
authorityHost: "https://login.partner.microsoftonline.cn",
|
246
|
+
}
|
247
|
+
);
|
248
|
+
```
|
249
|
+
|
230
250
|
Not all credentials require this configuration. Credentials that authenticate through a development tool, such as `AzureCliCredential`, use that tool's configuration. Similarly, `VisualStudioCodeCredential` accepts an `authorityHost` argument but defaults to the `authorityHost` matching Visual Studio Code's **Azure: Cloud** setting.
|
231
251
|
|
232
252
|
## Credential classes
|
@@ -369,5 +389,6 @@ If you'd like to contribute to this library, please read the [contributing guide
|
|
369
389
|
[defaultauthflow_image]: https://raw.githubusercontent.com/Azure/azure-sdk-for-js/main/sdk/identity/identity/images/mermaidjs/DefaultAzureCredentialAuthFlow.svg
|
370
390
|
[azure_identity_broker]: https://www.npmjs.com/package/@azure/identity-broker
|
371
391
|
[azure_identity_broker_readme]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity-broker
|
392
|
+
[authority_hosts]: https://learn.microsoft.com/javascript/api/@azure/identity/azureauthorityhosts
|
372
393
|
|
373
394
|
![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js%2Fsdk%2Fidentity%2Fidentity%2FREADME.png)
|
package/dist/index.js
CHANGED
@@ -6,18 +6,18 @@ var logger$m = require('@azure/logger');
|
|
6
6
|
var coreClient = require('@azure/core-client');
|
7
7
|
var coreUtil = require('@azure/core-util');
|
8
8
|
var coreRestPipeline = require('@azure/core-rest-pipeline');
|
9
|
-
var abortController = require('@azure/abort-controller');
|
10
9
|
var coreTracing = require('@azure/core-tracing');
|
11
10
|
var fs = require('fs');
|
12
11
|
var os = require('os');
|
13
12
|
var path = require('path');
|
13
|
+
var abortController = require('@azure/abort-controller');
|
14
14
|
var msalCommon = require('@azure/msal-node');
|
15
15
|
var open = require('open');
|
16
16
|
var promises = require('fs/promises');
|
17
17
|
var child_process = require('child_process');
|
18
18
|
var crypto = require('crypto');
|
19
|
-
var promises$1 = require('node:fs/promises');
|
20
19
|
var node_crypto = require('node:crypto');
|
20
|
+
var promises$1 = require('node:fs/promises');
|
21
21
|
|
22
22
|
function _interopNamespaceDefault(e) {
|
23
23
|
var n = Object.create(null);
|
@@ -44,7 +44,7 @@ var child_process__namespace = /*#__PURE__*/_interopNamespaceDefault(child_proce
|
|
44
44
|
/**
|
45
45
|
* Current version of the `@azure/identity` package.
|
46
46
|
*/
|
47
|
-
const SDK_VERSION = `4.5.0-beta.
|
47
|
+
const SDK_VERSION = `4.5.0-beta.2`;
|
48
48
|
/**
|
49
49
|
* The default client ID for authentication
|
50
50
|
* @internal
|
@@ -289,8 +289,9 @@ const CredentialUnavailableErrorName = "CredentialUnavailableError";
|
|
289
289
|
* an error that should halt the chain, it's caught and the chain continues
|
290
290
|
*/
|
291
291
|
class CredentialUnavailableError extends Error {
|
292
|
-
constructor(message) {
|
293
|
-
|
292
|
+
constructor(message, options) {
|
293
|
+
// @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
|
294
|
+
super(message, options);
|
294
295
|
this.name = CredentialUnavailableErrorName;
|
295
296
|
}
|
296
297
|
}
|
@@ -305,7 +306,7 @@ const AuthenticationErrorName = "AuthenticationError";
|
|
305
306
|
*/
|
306
307
|
class AuthenticationError extends Error {
|
307
308
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
308
|
-
constructor(statusCode, errorBody) {
|
309
|
+
constructor(statusCode, errorBody, options) {
|
309
310
|
let errorResponse = {
|
310
311
|
error: "unknown",
|
311
312
|
errorDescription: "An unknown error occurred and no additional details are available.",
|
@@ -323,8 +324,8 @@ class AuthenticationError extends Error {
|
|
323
324
|
catch (e) {
|
324
325
|
if (statusCode === 400) {
|
325
326
|
errorResponse = {
|
326
|
-
error: "
|
327
|
-
errorDescription:
|
327
|
+
error: "invalid_request",
|
328
|
+
errorDescription: `The service indicated that the request was invalid.\n\n${errorBody}`,
|
328
329
|
};
|
329
330
|
}
|
330
331
|
else {
|
@@ -341,7 +342,9 @@ class AuthenticationError extends Error {
|
|
341
342
|
errorDescription: "An unknown error occurred and no additional details are available.",
|
342
343
|
};
|
343
344
|
}
|
344
|
-
super(`${errorResponse.error} Status code: ${statusCode}\nMore details:\n${errorResponse.errorDescription}
|
345
|
+
super(`${errorResponse.error} Status code: ${statusCode}\nMore details:\n${errorResponse.errorDescription},`,
|
346
|
+
// @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
|
347
|
+
options);
|
345
348
|
this.statusCode = statusCode;
|
346
349
|
this.errorResponse = errorResponse;
|
347
350
|
// Ensure that this type reports the correct name
|
@@ -384,7 +387,9 @@ class AuthenticationRequiredError extends Error {
|
|
384
387
|
* Optional parameters. A message can be specified. The {@link GetTokenOptions} of the request can also be specified to more easily associate the error with the received parameters.
|
385
388
|
*/
|
386
389
|
options) {
|
387
|
-
super(options.message
|
390
|
+
super(options.message,
|
391
|
+
// @ts-expect-error - TypeScript does not recognize this until we use ES2022 as the target; however, all our major runtimes do support the `cause` property
|
392
|
+
options.cause ? { cause: options.cause } : undefined);
|
388
393
|
this.scopes = options.scopes;
|
389
394
|
this.getTokenOptions = options.getTokenOptions;
|
390
395
|
this.name = "AuthenticationRequiredError";
|
@@ -674,7 +679,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
674
679
|
// Here is a custom layer that allows us to abort requests that go through MSAL,
|
675
680
|
// since MSAL doesn't allow us to pass options all the way through.
|
676
681
|
generateAbortSignal(correlationId) {
|
677
|
-
const controller = new
|
682
|
+
const controller = new AbortController();
|
678
683
|
const controllers = this.abortControllers.get(correlationId) || [];
|
679
684
|
controllers.push(controller);
|
680
685
|
this.abortControllers.set(correlationId, controllers);
|
@@ -682,7 +687,7 @@ class IdentityClient extends coreClient.ServiceClient {
|
|
682
687
|
controller.signal.onabort = (...params) => {
|
683
688
|
this.abortControllers.set(correlationId, undefined);
|
684
689
|
if (existingOnAbort) {
|
685
|
-
existingOnAbort(
|
690
|
+
existingOnAbort.apply(controller.signal, params);
|
686
691
|
}
|
687
692
|
};
|
688
693
|
return controller.signal;
|
@@ -1524,6 +1529,10 @@ function calculateRegionalAuthority(regionalAuthority) {
|
|
1524
1529
|
|
1525
1530
|
// Copyright (c) Microsoft Corporation.
|
1526
1531
|
// Licensed under the MIT license.
|
1532
|
+
/**
|
1533
|
+
* The default logger used if no logger was passed in by the credential.
|
1534
|
+
*/
|
1535
|
+
const msalLogger = credentialLogger("MsalClient");
|
1527
1536
|
/**
|
1528
1537
|
* A call to open(), but mockable
|
1529
1538
|
* @internal
|
@@ -1531,13 +1540,6 @@ function calculateRegionalAuthority(regionalAuthority) {
|
|
1531
1540
|
const interactiveBrowserMockable = {
|
1532
1541
|
open,
|
1533
1542
|
};
|
1534
|
-
|
1535
|
-
// Copyright (c) Microsoft Corporation.
|
1536
|
-
// Licensed under the MIT license.
|
1537
|
-
/**
|
1538
|
-
* The default logger used if no logger was passed in by the credential.
|
1539
|
-
*/
|
1540
|
-
const msalLogger = credentialLogger("MsalClient");
|
1541
1543
|
/**
|
1542
1544
|
* Generates the configuration for MSAL (Microsoft Authentication Library).
|
1543
1545
|
*
|
@@ -1983,8 +1985,14 @@ class ClientAssertionCredential {
|
|
1983
1985
|
* @param options - Options for configuring the client which makes the authentication request.
|
1984
1986
|
*/
|
1985
1987
|
constructor(tenantId, clientId, getAssertion, options = {}) {
|
1986
|
-
if (!tenantId
|
1987
|
-
throw new
|
1988
|
+
if (!tenantId) {
|
1989
|
+
throw new CredentialUnavailableError("ClientAssertionCredential: tenantId is a required parameter.");
|
1990
|
+
}
|
1991
|
+
if (!clientId) {
|
1992
|
+
throw new CredentialUnavailableError("ClientAssertionCredential: clientId is a required parameter.");
|
1993
|
+
}
|
1994
|
+
if (!getAssertion) {
|
1995
|
+
throw new CredentialUnavailableError("ClientAssertionCredential: clientAssertion is a required parameter.");
|
1988
1996
|
}
|
1989
1997
|
this.tenantId = tenantId;
|
1990
1998
|
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
|
@@ -2059,10 +2067,20 @@ class WorkloadIdentityCredential {
|
|
2059
2067
|
if (tenantId) {
|
2060
2068
|
checkTenantId(logger$g, tenantId);
|
2061
2069
|
}
|
2062
|
-
if (clientId
|
2063
|
-
|
2064
|
-
|
2070
|
+
if (!clientId) {
|
2071
|
+
throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_CLIENT_ID".
|
2072
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
|
2065
2073
|
}
|
2074
|
+
if (!tenantId) {
|
2075
|
+
throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_TENANT_ID".
|
2076
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
|
2077
|
+
}
|
2078
|
+
if (!this.federatedTokenFilePath) {
|
2079
|
+
throw new CredentialUnavailableError(`${credentialName$4}: is unavailable. federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_FEDERATED_TOKEN_FILE".
|
2080
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
|
2081
|
+
}
|
2082
|
+
logger$g.info(`Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`);
|
2083
|
+
this.client = new ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), options);
|
2066
2084
|
}
|
2067
2085
|
/**
|
2068
2086
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
@@ -2078,7 +2096,7 @@ class WorkloadIdentityCredential {
|
|
2078
2096
|
In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
|
2079
2097
|
"AZURE_TENANT_ID",
|
2080
2098
|
"AZURE_CLIENT_ID",
|
2081
|
-
"AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot
|
2099
|
+
"AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;
|
2082
2100
|
logger$g.info(errorMessage);
|
2083
2101
|
throw new CredentialUnavailableError(errorMessage);
|
2084
2102
|
}
|
@@ -2217,6 +2235,7 @@ class MsalMsiProvider {
|
|
2217
2235
|
// We will continue to implement these features in the Identity library.
|
2218
2236
|
const identitySource = this.managedIdentityApp.getManagedIdentitySource();
|
2219
2237
|
const isImdsMsi = identitySource === "DefaultToImds" || identitySource === "Imds"; // Neither actually checks that IMDS endpoint is available, just that it's the source the MSAL _would_ try to use.
|
2238
|
+
logger$e.getToken.info(`MSAL Identity source: ${identitySource}`);
|
2220
2239
|
if (isTokenExchangeMsi) {
|
2221
2240
|
// In the AKS scenario we will use the existing tokenExchangeMsi indefinitely.
|
2222
2241
|
logger$e.getToken.info("Using the token exchange managed identity.");
|
@@ -2228,7 +2247,7 @@ class MsalMsiProvider {
|
|
2228
2247
|
resourceId: this.resourceId,
|
2229
2248
|
});
|
2230
2249
|
if (result === null) {
|
2231
|
-
throw new CredentialUnavailableError("
|
2250
|
+
throw new CredentialUnavailableError("Attempted to use the token exchange managed identity, but received a null response.");
|
2232
2251
|
}
|
2233
2252
|
return result;
|
2234
2253
|
}
|
@@ -2244,7 +2263,7 @@ class MsalMsiProvider {
|
|
2244
2263
|
resourceId: this.resourceId,
|
2245
2264
|
});
|
2246
2265
|
if (!isAvailable) {
|
2247
|
-
throw new CredentialUnavailableError(`ManagedIdentityCredential:
|
2266
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: Attempted to use the IMDS endpoint, but it is not available.`);
|
2248
2267
|
}
|
2249
2268
|
}
|
2250
2269
|
// If we got this far, it means:
|
@@ -2270,9 +2289,9 @@ class MsalMsiProvider {
|
|
2270
2289
|
throw err;
|
2271
2290
|
}
|
2272
2291
|
if (isNetworkError(err)) {
|
2273
|
-
throw new CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}
|
2292
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: Network unreachable. Message: ${err.message}`, { cause: err });
|
2274
2293
|
}
|
2275
|
-
throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}
|
2294
|
+
throw new CredentialUnavailableError(`ManagedIdentityCredential: Authentication failed. Message ${err.message}`, { cause: err });
|
2276
2295
|
}
|
2277
2296
|
});
|
2278
2297
|
}
|
@@ -2289,7 +2308,7 @@ class MsalMsiProvider {
|
|
2289
2308
|
});
|
2290
2309
|
};
|
2291
2310
|
if (!msalToken) {
|
2292
|
-
throw createError("No response");
|
2311
|
+
throw createError("No response.");
|
2293
2312
|
}
|
2294
2313
|
if (!msalToken.expiresOn) {
|
2295
2314
|
throw createError(`Response had no "expiresOn" property.`);
|
@@ -2848,33 +2867,45 @@ class AzurePowerShellCredential {
|
|
2848
2867
|
commandStack.shift();
|
2849
2868
|
continue;
|
2850
2869
|
}
|
2851
|
-
let tenantSection = "";
|
2852
|
-
if (tenantId) {
|
2853
|
-
tenantSection = `-TenantId "${tenantId}"`;
|
2854
|
-
}
|
2855
2870
|
const results = await runCommands([
|
2856
2871
|
[
|
2857
2872
|
powerShellCommand,
|
2858
2873
|
"-NoProfile",
|
2859
2874
|
"-NonInteractive",
|
2860
2875
|
"-Command",
|
2861
|
-
|
2862
|
-
|
2863
|
-
|
2864
|
-
|
2865
|
-
|
2866
|
-
|
2867
|
-
|
2868
|
-
|
2876
|
+
`
|
2877
|
+
$tenantId = "${tenantId !== null && tenantId !== void 0 ? tenantId : ""}"
|
2878
|
+
$m = Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru
|
2879
|
+
$useSecureString = $m.Version -ge [version]'2.17.0'
|
2880
|
+
|
2881
|
+
$params = @{
|
2882
|
+
ResourceUrl = "${resource}"
|
2883
|
+
}
|
2884
|
+
|
2885
|
+
if ($tenantId.Length -gt 0) {
|
2886
|
+
$params["TenantId"] = $tenantId
|
2887
|
+
}
|
2888
|
+
|
2889
|
+
if ($useSecureString) {
|
2890
|
+
$params["AsSecureString"] = $true
|
2891
|
+
}
|
2892
|
+
|
2893
|
+
$token = Get-AzAccessToken @params
|
2894
|
+
|
2895
|
+
$result = New-Object -TypeName PSObject
|
2896
|
+
$result | Add-Member -MemberType NoteProperty -Name ExpiresOn -Value $token.ExpiresOn
|
2897
|
+
if ($useSecureString) {
|
2898
|
+
$result | Add-Member -MemberType NoteProperty -Name Token -Value (ConvertFrom-SecureString -AsPlainText $token.Token)
|
2899
|
+
} else {
|
2900
|
+
$result | Add-Member -MemberType NoteProperty -Name Token -Value $token.Token
|
2901
|
+
}
|
2902
|
+
|
2903
|
+
Write-Output (ConvertTo-Json $result)
|
2904
|
+
`,
|
2869
2905
|
],
|
2870
2906
|
]);
|
2871
|
-
const result = results[
|
2872
|
-
|
2873
|
-
return JSON.parse(result);
|
2874
|
-
}
|
2875
|
-
catch (e) {
|
2876
|
-
throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
|
2877
|
-
}
|
2907
|
+
const result = results[0];
|
2908
|
+
return parseJsonToken(result);
|
2878
2909
|
}
|
2879
2910
|
throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
|
2880
2911
|
}
|
@@ -2921,6 +2952,38 @@ class AzurePowerShellCredential {
|
|
2921
2952
|
});
|
2922
2953
|
}
|
2923
2954
|
}
|
2955
|
+
/**
|
2956
|
+
*
|
2957
|
+
* @internal
|
2958
|
+
*/
|
2959
|
+
async function parseJsonToken(result) {
|
2960
|
+
const jsonRegex = /{[^{}]*}/g;
|
2961
|
+
const matches = result.match(jsonRegex);
|
2962
|
+
let resultWithoutToken = result;
|
2963
|
+
if (matches) {
|
2964
|
+
try {
|
2965
|
+
for (const item of matches) {
|
2966
|
+
try {
|
2967
|
+
const jsonContent = JSON.parse(item);
|
2968
|
+
if (jsonContent === null || jsonContent === void 0 ? void 0 : jsonContent.Token) {
|
2969
|
+
resultWithoutToken = resultWithoutToken.replace(item, "");
|
2970
|
+
if (resultWithoutToken) {
|
2971
|
+
logger$b.getToken.warning(resultWithoutToken);
|
2972
|
+
}
|
2973
|
+
return jsonContent;
|
2974
|
+
}
|
2975
|
+
}
|
2976
|
+
catch (e) {
|
2977
|
+
continue;
|
2978
|
+
}
|
2979
|
+
}
|
2980
|
+
}
|
2981
|
+
catch (e) {
|
2982
|
+
throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
|
2983
|
+
}
|
2984
|
+
}
|
2985
|
+
throw new Error(`No access token found in the output. Received output: ${result}`);
|
2986
|
+
}
|
2924
2987
|
|
2925
2988
|
// Copyright (c) Microsoft Corporation.
|
2926
2989
|
// Licensed under the MIT license.
|
@@ -3053,7 +3116,8 @@ class ClientCertificateCredential {
|
|
3053
3116
|
});
|
3054
3117
|
}
|
3055
3118
|
async buildClientCertificate() {
|
3056
|
-
|
3119
|
+
var _a;
|
3120
|
+
const parts = await parseCertificate(this.certificateConfiguration, (_a = this.sendCertificateChain) !== null && _a !== void 0 ? _a : false);
|
3057
3121
|
let privateKey;
|
3058
3122
|
if (this.certificateConfiguration.certificatePassword !== undefined) {
|
3059
3123
|
privateKey = crypto.createPrivateKey({
|
@@ -3076,34 +3140,41 @@ class ClientCertificateCredential {
|
|
3076
3140
|
x5c: parts.x5c,
|
3077
3141
|
};
|
3078
3142
|
}
|
3079
|
-
|
3080
|
-
|
3081
|
-
|
3082
|
-
|
3083
|
-
|
3084
|
-
|
3085
|
-
|
3086
|
-
|
3087
|
-
|
3088
|
-
|
3089
|
-
|
3090
|
-
|
3091
|
-
|
3092
|
-
|
3093
|
-
|
3094
|
-
|
3095
|
-
|
3143
|
+
}
|
3144
|
+
/**
|
3145
|
+
* Parses a certificate into its relevant parts
|
3146
|
+
*
|
3147
|
+
* @param certificateConfiguration - The certificate contents or path to the certificate
|
3148
|
+
* @param sendCertificateChain - true if the entire certificate chain should be sent for SNI, false otherwise
|
3149
|
+
* @returns The parsed certificate parts and the certificate contents
|
3150
|
+
*/
|
3151
|
+
async function parseCertificate(certificateConfiguration, sendCertificateChain) {
|
3152
|
+
const certificate = certificateConfiguration.certificate;
|
3153
|
+
const certificatePath = certificateConfiguration.certificatePath;
|
3154
|
+
const certificateContents = certificate || (await promises.readFile(certificatePath, "utf8"));
|
3155
|
+
const x5c = sendCertificateChain ? certificateContents : undefined;
|
3156
|
+
const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
|
3157
|
+
const publicKeys = [];
|
3158
|
+
// Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
|
3159
|
+
let match;
|
3160
|
+
do {
|
3161
|
+
match = certificatePattern.exec(certificateContents);
|
3162
|
+
if (match) {
|
3163
|
+
publicKeys.push(match[3]);
|
3096
3164
|
}
|
3097
|
-
|
3098
|
-
|
3099
|
-
|
3100
|
-
|
3101
|
-
|
3102
|
-
|
3103
|
-
|
3104
|
-
|
3105
|
-
|
3106
|
-
|
3165
|
+
} while (match);
|
3166
|
+
if (publicKeys.length === 0) {
|
3167
|
+
throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
|
3168
|
+
}
|
3169
|
+
const thumbprint = crypto.createHash("sha1")
|
3170
|
+
.update(Buffer.from(publicKeys[0], "base64"))
|
3171
|
+
.digest("hex")
|
3172
|
+
.toUpperCase();
|
3173
|
+
return {
|
3174
|
+
certificateContents,
|
3175
|
+
thumbprint,
|
3176
|
+
x5c,
|
3177
|
+
};
|
3107
3178
|
}
|
3108
3179
|
|
3109
3180
|
// Copyright (c) Microsoft Corporation.
|
@@ -3129,8 +3200,14 @@ class ClientSecretCredential {
|
|
3129
3200
|
* @param options - Options for configuring the client which makes the authentication request.
|
3130
3201
|
*/
|
3131
3202
|
constructor(tenantId, clientId, clientSecret, options = {}) {
|
3132
|
-
if (!tenantId
|
3133
|
-
throw new
|
3203
|
+
if (!tenantId) {
|
3204
|
+
throw new CredentialUnavailableError("ClientSecretCredential: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
|
3205
|
+
}
|
3206
|
+
if (!clientId) {
|
3207
|
+
throw new CredentialUnavailableError("ClientSecretCredential: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
|
3208
|
+
}
|
3209
|
+
if (!clientSecret) {
|
3210
|
+
throw new CredentialUnavailableError("ClientSecretCredential: clientSecret is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.");
|
3134
3211
|
}
|
3135
3212
|
this.clientSecret = clientSecret;
|
3136
3213
|
this.tenantId = tenantId;
|
@@ -3176,8 +3253,17 @@ class UsernamePasswordCredential {
|
|
3176
3253
|
* @param options - Options for configuring the client which makes the authentication request.
|
3177
3254
|
*/
|
3178
3255
|
constructor(tenantId, clientId, username, password, options = {}) {
|
3179
|
-
if (!tenantId
|
3180
|
-
throw new
|
3256
|
+
if (!tenantId) {
|
3257
|
+
throw new CredentialUnavailableError("UsernamePasswordCredential: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
3258
|
+
}
|
3259
|
+
if (!clientId) {
|
3260
|
+
throw new CredentialUnavailableError("UsernamePasswordCredential: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
3261
|
+
}
|
3262
|
+
if (!username) {
|
3263
|
+
throw new CredentialUnavailableError("UsernamePasswordCredential: username is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
3264
|
+
}
|
3265
|
+
if (!password) {
|
3266
|
+
throw new CredentialUnavailableError("UsernamePasswordCredential: password is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/usernamepasswordcredential/troubleshoot.");
|
3181
3267
|
}
|
3182
3268
|
this.tenantId = tenantId;
|
3183
3269
|
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
|
@@ -3224,6 +3310,7 @@ const AllSupportedEnvironmentVariables = [
|
|
3224
3310
|
"AZURE_USERNAME",
|
3225
3311
|
"AZURE_PASSWORD",
|
3226
3312
|
"AZURE_ADDITIONALLY_ALLOWED_TENANTS",
|
3313
|
+
"AZURE_CLIENT_SEND_CERTIFICATE_CHAIN",
|
3227
3314
|
];
|
3228
3315
|
function getAdditionallyAllowedTenants() {
|
3229
3316
|
var _a;
|
@@ -3232,6 +3319,13 @@ function getAdditionallyAllowedTenants() {
|
|
3232
3319
|
}
|
3233
3320
|
const credentialName$2 = "EnvironmentCredential";
|
3234
3321
|
const logger$6 = credentialLogger(credentialName$2);
|
3322
|
+
function getSendCertificateChain() {
|
3323
|
+
var _a;
|
3324
|
+
const sendCertificateChain = ((_a = process.env.AZURE_CLIENT_SEND_CERTIFICATE_CHAIN) !== null && _a !== void 0 ? _a : "").toLowerCase();
|
3325
|
+
const result = sendCertificateChain === "true" || sendCertificateChain === "1";
|
3326
|
+
logger$6.verbose(`AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: ${process.env.AZURE_CLIENT_SEND_CERTIFICATE_CHAIN}; sendCertificateChain: ${result}`);
|
3327
|
+
return result;
|
3328
|
+
}
|
3235
3329
|
/**
|
3236
3330
|
* Enables authentication to Microsoft Entra ID using a client secret or certificate, or as a user
|
3237
3331
|
* with a username and password.
|
@@ -3251,6 +3345,7 @@ class EnvironmentCredential {
|
|
3251
3345
|
* - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
|
3252
3346
|
* - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
|
3253
3347
|
* - `AZURE_CLIENT_CERTIFICATE_PASSWORD`: (optional) password for the certificate file.
|
3348
|
+
* - `AZURE_CLIENT_SEND_CERTIFICATE_CHAIN`: (optional) indicates that the certificate chain should be set in x5c header to support subject name / issuer based authentication.
|
3254
3349
|
*
|
3255
3350
|
* Alternatively, users can provide environment variables for username and password authentication:
|
3256
3351
|
* - `AZURE_USERNAME`: Username to authenticate with.
|
@@ -3268,7 +3363,8 @@ class EnvironmentCredential {
|
|
3268
3363
|
logger$6.info(`Found the following environment variables: ${assigned}`);
|
3269
3364
|
const tenantId = process.env.AZURE_TENANT_ID, clientId = process.env.AZURE_CLIENT_ID, clientSecret = process.env.AZURE_CLIENT_SECRET;
|
3270
3365
|
const additionallyAllowedTenantIds = getAdditionallyAllowedTenants();
|
3271
|
-
const
|
3366
|
+
const sendCertificateChain = getSendCertificateChain();
|
3367
|
+
const newOptions = Object.assign(Object.assign({}, options), { additionallyAllowedTenantIds, sendCertificateChain });
|
3272
3368
|
if (tenantId) {
|
3273
3369
|
checkTenantId(logger$6, tenantId);
|
3274
3370
|
}
|
@@ -3529,7 +3625,7 @@ class InteractiveBrowserCredential {
|
|
3529
3625
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
3530
3626
|
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
|
3531
3627
|
*
|
3532
|
-
* If the token can't be retrieved silently, this method will
|
3628
|
+
* If the token can't be retrieved silently, this method will always generate a challenge for the user.
|
3533
3629
|
*
|
3534
3630
|
* On Node.js, this credential has [Proof Key for Code Exchange (PKCE)](https://datatracker.ietf.org/doc/html/rfc7636) enabled by default.
|
3535
3631
|
* PKCE is a security feature that mitigates authentication code interception attacks.
|
@@ -3615,7 +3711,7 @@ class DeviceCodeCredential {
|
|
3615
3711
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
3616
3712
|
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
|
3617
3713
|
*
|
3618
|
-
* If the token can't be retrieved silently, this method will
|
3714
|
+
* If the token can't be retrieved silently, this method will always generate a challenge for the user.
|
3619
3715
|
*
|
3620
3716
|
* @param scopes - The list of scopes for which the token will have access.
|
3621
3717
|
* @param options - The options used to configure any requests this
|
@@ -3649,8 +3745,17 @@ class AzurePipelinesCredential {
|
|
3649
3745
|
* @param options - The identity client options to use for authentication.
|
3650
3746
|
*/
|
3651
3747
|
constructor(tenantId, clientId, serviceConnectionId, systemAccessToken, options) {
|
3652
|
-
if (!clientId
|
3653
|
-
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable.
|
3748
|
+
if (!clientId) {
|
3749
|
+
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. clientId is a required parameter.`);
|
3750
|
+
}
|
3751
|
+
if (!tenantId) {
|
3752
|
+
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. tenantId is a required parameter.`);
|
3753
|
+
}
|
3754
|
+
if (!serviceConnectionId) {
|
3755
|
+
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. serviceConnectionId is a required parameter.`);
|
3756
|
+
}
|
3757
|
+
if (!systemAccessToken) {
|
3758
|
+
throw new CredentialUnavailableError(`${credentialName$1}: is unavailable. systemAccessToken is a required parameter.`);
|
3654
3759
|
}
|
3655
3760
|
this.identityClient = new IdentityClient(options);
|
3656
3761
|
checkTenantId(logger$2, tenantId);
|
@@ -3703,30 +3808,45 @@ class AzurePipelinesCredential {
|
|
3703
3808
|
}),
|
3704
3809
|
});
|
3705
3810
|
const response = await this.identityClient.sendRequest(request);
|
3706
|
-
|
3707
|
-
|
3708
|
-
|
3709
|
-
|
3811
|
+
return handleOidcResponse(response);
|
3812
|
+
}
|
3813
|
+
}
|
3814
|
+
function handleOidcResponse(response) {
|
3815
|
+
const text = response.bodyAsText;
|
3816
|
+
if (!text) {
|
3817
|
+
logger$2.error(`${credentialName$1}: Authentication Failed. Received null token from OIDC request. Response status- ${response.status}. Complete response - ${JSON.stringify(response)}`);
|
3818
|
+
throw new AuthenticationError(response.status, {
|
3819
|
+
error: `${credentialName$1}: Authentication Failed. Received null token from OIDC request.`,
|
3820
|
+
error_description: `${JSON.stringify(response)}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,
|
3821
|
+
});
|
3822
|
+
}
|
3823
|
+
try {
|
3824
|
+
const result = JSON.parse(text);
|
3825
|
+
if (result === null || result === void 0 ? void 0 : result.oidcToken) {
|
3826
|
+
return result.oidcToken;
|
3710
3827
|
}
|
3711
|
-
|
3712
|
-
const
|
3713
|
-
|
3714
|
-
|
3715
|
-
|
3716
|
-
else {
|
3717
|
-
let errorMessage = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
|
3718
|
-
if (response.status !== 200) {
|
3719
|
-
errorMessage += `Response = ${JSON.stringify(result)}`;
|
3720
|
-
}
|
3721
|
-
logger$2.error(errorMessage);
|
3722
|
-
throw new AuthenticationError(response.status, errorMessage);
|
3828
|
+
else {
|
3829
|
+
const errorMessage = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
|
3830
|
+
let errorDescription = ``;
|
3831
|
+
if (response.status !== 200) {
|
3832
|
+
errorDescription = `Complete response - ${JSON.stringify(result)}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`;
|
3723
3833
|
}
|
3834
|
+
logger$2.error(errorMessage);
|
3835
|
+
logger$2.error(errorDescription);
|
3836
|
+
throw new AuthenticationError(response.status, {
|
3837
|
+
error: errorMessage,
|
3838
|
+
error_description: errorDescription,
|
3839
|
+
});
|
3724
3840
|
}
|
3725
|
-
|
3726
|
-
|
3727
|
-
|
3728
|
-
|
3729
|
-
|
3841
|
+
}
|
3842
|
+
catch (e) {
|
3843
|
+
const errorDetails = `${credentialName$1}: Authentication Failed. oidcToken field not detected in the response.`;
|
3844
|
+
logger$2.error(`Response from service = ${text} and error message = ${e.message}`);
|
3845
|
+
logger$2.error(errorDetails);
|
3846
|
+
throw new AuthenticationError(response.status, {
|
3847
|
+
error: errorDetails,
|
3848
|
+
error_description: `Response = ${text}. See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/azurepipelinescredential/troubleshoot`,
|
3849
|
+
});
|
3730
3850
|
}
|
3731
3851
|
}
|
3732
3852
|
|
@@ -3797,11 +3917,17 @@ class OnBehalfOfCredential {
|
|
3797
3917
|
const { certificatePath, sendCertificateChain } = options;
|
3798
3918
|
const { getAssertion } = options;
|
3799
3919
|
const { tenantId, clientId, userAssertionToken, additionallyAllowedTenants: additionallyAllowedTenantIds, } = options;
|
3800
|
-
if (!tenantId
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
3804
|
-
throw new
|
3920
|
+
if (!tenantId) {
|
3921
|
+
throw new CredentialUnavailableError(`${credentialName}: tenantId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
3922
|
+
}
|
3923
|
+
if (!clientId) {
|
3924
|
+
throw new CredentialUnavailableError(`${credentialName}: clientId is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
3925
|
+
}
|
3926
|
+
if (!clientSecret && !certificatePath && !getAssertion) {
|
3927
|
+
throw new CredentialUnavailableError(`${credentialName}: You must provide one of clientSecret, certificatePath, or a getAssertion callback but none were provided. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
3928
|
+
}
|
3929
|
+
if (!userAssertionToken) {
|
3930
|
+
throw new CredentialUnavailableError(`${credentialName}: userAssertionToken is a required parameter. To troubleshoot, visit https://aka.ms/azsdk/js/identity/serviceprincipalauthentication/troubleshoot.`);
|
3805
3931
|
}
|
3806
3932
|
this.certificatePath = certificatePath;
|
3807
3933
|
this.clientSecret = clientSecret;
|