@azure/identity 4.4.1 → 4.5.0-alpha.20240813.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 +169 -85
- 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 +14 -5
- package/dist-esm/src/credentials/azurePipelinesCredential.js.map +1 -1
- package/dist-esm/src/credentials/azurePowerShellCredential.js +30 -13
- 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 +4 -4
- 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.
|
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`);
|
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`);
|
2065
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,27 +2867,44 @@ 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[
|
2907
|
+
const result = results[0];
|
2872
2908
|
return parseJsonToken(result);
|
2873
2909
|
}
|
2874
2910
|
throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
|
@@ -3080,7 +3116,8 @@ class ClientCertificateCredential {
|
|
3080
3116
|
});
|
3081
3117
|
}
|
3082
3118
|
async buildClientCertificate() {
|
3083
|
-
|
3119
|
+
var _a;
|
3120
|
+
const parts = await parseCertificate(this.certificateConfiguration, (_a = this.sendCertificateChain) !== null && _a !== void 0 ? _a : false);
|
3084
3121
|
let privateKey;
|
3085
3122
|
if (this.certificateConfiguration.certificatePassword !== undefined) {
|
3086
3123
|
privateKey = crypto.createPrivateKey({
|
@@ -3103,34 +3140,41 @@ class ClientCertificateCredential {
|
|
3103
3140
|
x5c: parts.x5c,
|
3104
3141
|
};
|
3105
3142
|
}
|
3106
|
-
|
3107
|
-
|
3108
|
-
|
3109
|
-
|
3110
|
-
|
3111
|
-
|
3112
|
-
|
3113
|
-
|
3114
|
-
|
3115
|
-
|
3116
|
-
|
3117
|
-
|
3118
|
-
|
3119
|
-
|
3120
|
-
|
3121
|
-
|
3122
|
-
|
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]);
|
3123
3164
|
}
|
3124
|
-
|
3125
|
-
|
3126
|
-
|
3127
|
-
|
3128
|
-
|
3129
|
-
|
3130
|
-
|
3131
|
-
|
3132
|
-
|
3133
|
-
|
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
|
+
};
|
3134
3178
|
}
|
3135
3179
|
|
3136
3180
|
// Copyright (c) Microsoft Corporation.
|
@@ -3156,8 +3200,14 @@ class ClientSecretCredential {
|
|
3156
3200
|
* @param options - Options for configuring the client which makes the authentication request.
|
3157
3201
|
*/
|
3158
3202
|
constructor(tenantId, clientId, clientSecret, options = {}) {
|
3159
|
-
if (!tenantId
|
3160
|
-
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.");
|
3161
3211
|
}
|
3162
3212
|
this.clientSecret = clientSecret;
|
3163
3213
|
this.tenantId = tenantId;
|
@@ -3203,8 +3253,17 @@ class UsernamePasswordCredential {
|
|
3203
3253
|
* @param options - Options for configuring the client which makes the authentication request.
|
3204
3254
|
*/
|
3205
3255
|
constructor(tenantId, clientId, username, password, options = {}) {
|
3206
|
-
if (!tenantId
|
3207
|
-
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.");
|
3208
3267
|
}
|
3209
3268
|
this.tenantId = tenantId;
|
3210
3269
|
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
|
@@ -3251,6 +3310,7 @@ const AllSupportedEnvironmentVariables = [
|
|
3251
3310
|
"AZURE_USERNAME",
|
3252
3311
|
"AZURE_PASSWORD",
|
3253
3312
|
"AZURE_ADDITIONALLY_ALLOWED_TENANTS",
|
3313
|
+
"AZURE_CLIENT_SEND_CERTIFICATE_CHAIN",
|
3254
3314
|
];
|
3255
3315
|
function getAdditionallyAllowedTenants() {
|
3256
3316
|
var _a;
|
@@ -3259,6 +3319,13 @@ function getAdditionallyAllowedTenants() {
|
|
3259
3319
|
}
|
3260
3320
|
const credentialName$2 = "EnvironmentCredential";
|
3261
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
|
+
}
|
3262
3329
|
/**
|
3263
3330
|
* Enables authentication to Microsoft Entra ID using a client secret or certificate, or as a user
|
3264
3331
|
* with a username and password.
|
@@ -3278,6 +3345,7 @@ class EnvironmentCredential {
|
|
3278
3345
|
* - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
|
3279
3346
|
* - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
|
3280
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.
|
3281
3349
|
*
|
3282
3350
|
* Alternatively, users can provide environment variables for username and password authentication:
|
3283
3351
|
* - `AZURE_USERNAME`: Username to authenticate with.
|
@@ -3295,7 +3363,8 @@ class EnvironmentCredential {
|
|
3295
3363
|
logger$6.info(`Found the following environment variables: ${assigned}`);
|
3296
3364
|
const tenantId = process.env.AZURE_TENANT_ID, clientId = process.env.AZURE_CLIENT_ID, clientSecret = process.env.AZURE_CLIENT_SECRET;
|
3297
3365
|
const additionallyAllowedTenantIds = getAdditionallyAllowedTenants();
|
3298
|
-
const
|
3366
|
+
const sendCertificateChain = getSendCertificateChain();
|
3367
|
+
const newOptions = Object.assign(Object.assign({}, options), { additionallyAllowedTenantIds, sendCertificateChain });
|
3299
3368
|
if (tenantId) {
|
3300
3369
|
checkTenantId(logger$6, tenantId);
|
3301
3370
|
}
|
@@ -3556,7 +3625,7 @@ class InteractiveBrowserCredential {
|
|
3556
3625
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
3557
3626
|
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
|
3558
3627
|
*
|
3559
|
-
* 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.
|
3560
3629
|
*
|
3561
3630
|
* On Node.js, this credential has [Proof Key for Code Exchange (PKCE)](https://datatracker.ietf.org/doc/html/rfc7636) enabled by default.
|
3562
3631
|
* PKCE is a security feature that mitigates authentication code interception attacks.
|
@@ -3642,7 +3711,7 @@ class DeviceCodeCredential {
|
|
3642
3711
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
3643
3712
|
* If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.
|
3644
3713
|
*
|
3645
|
-
* 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.
|
3646
3715
|
*
|
3647
3716
|
* @param scopes - The list of scopes for which the token will have access.
|
3648
3717
|
* @param options - The options used to configure any requests this
|
@@ -3676,8 +3745,17 @@ class AzurePipelinesCredential {
|
|
3676
3745
|
* @param options - The identity client options to use for authentication.
|
3677
3746
|
*/
|
3678
3747
|
constructor(tenantId, clientId, serviceConnectionId, systemAccessToken, options) {
|
3679
|
-
if (!clientId
|
3680
|
-
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.`);
|
3681
3759
|
}
|
3682
3760
|
this.identityClient = new IdentityClient(options);
|
3683
3761
|
checkTenantId(logger$2, tenantId);
|
@@ -3839,11 +3917,17 @@ class OnBehalfOfCredential {
|
|
3839
3917
|
const { certificatePath, sendCertificateChain } = options;
|
3840
3918
|
const { getAssertion } = options;
|
3841
3919
|
const { tenantId, clientId, userAssertionToken, additionallyAllowedTenants: additionallyAllowedTenantIds, } = options;
|
3842
|
-
if (!tenantId
|
3843
|
-
|
3844
|
-
|
3845
|
-
|
3846
|
-
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.`);
|
3847
3931
|
}
|
3848
3932
|
this.certificatePath = certificatePath;
|
3849
3933
|
this.clientSecret = clientSecret;
|