@azure/identity 4.13.0 → 4.14.0-alpha.20251106.5
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.
- package/README.md +1 -1
- package/dist/browser/constants.d.ts +1 -1
- package/dist/browser/constants.d.ts.map +1 -1
- package/dist/browser/constants.js +1 -1
- package/dist/browser/constants.js.map +1 -1
- package/dist/browser/credentials/chainedTokenCredential.d.ts +1 -1
- package/dist/browser/credentials/chainedTokenCredential.js +1 -1
- package/dist/browser/credentials/chainedTokenCredential.js.map +1 -1
- package/dist/browser/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
- package/dist/browser/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
- package/dist/browser/credentials/workloadIdentityCredentialOptions.js.map +1 -1
- package/dist/browser/util/certificatesUtils.d.ts +13 -0
- package/dist/browser/util/certificatesUtils.d.ts.map +1 -0
- package/dist/browser/util/certificatesUtils.js +47 -0
- package/dist/browser/util/certificatesUtils.js.map +1 -0
- package/dist/commonjs/constants.d.ts +1 -1
- package/dist/commonjs/constants.d.ts.map +1 -1
- package/dist/commonjs/constants.js +1 -1
- package/dist/commonjs/constants.js.map +1 -1
- package/dist/commonjs/credentials/chainedTokenCredential.d.ts +1 -1
- package/dist/commonjs/credentials/chainedTokenCredential.js +1 -1
- package/dist/commonjs/credentials/chainedTokenCredential.js.map +1 -1
- package/dist/commonjs/credentials/clientCertificateCredential.d.ts.map +1 -1
- package/dist/commonjs/credentials/clientCertificateCredential.js +2 -13
- package/dist/commonjs/credentials/clientCertificateCredential.js.map +1 -1
- package/dist/commonjs/credentials/defaultAzureCredential.d.ts +1 -1
- package/dist/commonjs/credentials/defaultAzureCredential.js +1 -1
- package/dist/commonjs/credentials/defaultAzureCredential.js.map +1 -1
- package/dist/commonjs/credentials/workloadIdentityCredential.d.ts +20 -0
- package/dist/commonjs/credentials/workloadIdentityCredential.d.ts.map +1 -1
- package/dist/commonjs/credentials/workloadIdentityCredential.js +192 -14
- package/dist/commonjs/credentials/workloadIdentityCredential.js.map +1 -1
- package/dist/commonjs/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
- package/dist/commonjs/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
- package/dist/commonjs/credentials/workloadIdentityCredentialOptions.js.map +1 -1
- package/dist/commonjs/tsdoc-metadata.json +1 -1
- package/dist/commonjs/util/certificatesUtils.d.ts +13 -0
- package/dist/commonjs/util/certificatesUtils.d.ts.map +1 -0
- package/dist/commonjs/util/certificatesUtils.js +51 -0
- package/dist/commonjs/util/certificatesUtils.js.map +1 -0
- package/dist/esm/constants.d.ts +1 -1
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.js +1 -1
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/credentials/chainedTokenCredential.d.ts +1 -1
- package/dist/esm/credentials/chainedTokenCredential.js +1 -1
- package/dist/esm/credentials/chainedTokenCredential.js.map +1 -1
- package/dist/esm/credentials/clientCertificateCredential.d.ts.map +1 -1
- package/dist/esm/credentials/clientCertificateCredential.js +2 -13
- package/dist/esm/credentials/clientCertificateCredential.js.map +1 -1
- package/dist/esm/credentials/defaultAzureCredential.d.ts +1 -1
- package/dist/esm/credentials/defaultAzureCredential.js +1 -1
- package/dist/esm/credentials/defaultAzureCredential.js.map +1 -1
- package/dist/esm/credentials/workloadIdentityCredential.d.ts +20 -0
- package/dist/esm/credentials/workloadIdentityCredential.d.ts.map +1 -1
- package/dist/esm/credentials/workloadIdentityCredential.js +191 -14
- package/dist/esm/credentials/workloadIdentityCredential.js.map +1 -1
- package/dist/esm/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
- package/dist/esm/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
- package/dist/esm/credentials/workloadIdentityCredentialOptions.js.map +1 -1
- package/dist/esm/util/certificatesUtils.d.ts +13 -0
- package/dist/esm/util/certificatesUtils.d.ts.map +1 -0
- package/dist/esm/util/certificatesUtils.js +47 -0
- package/dist/esm/util/certificatesUtils.js.map +1 -0
- package/dist/workerd/constants.d.ts +1 -1
- package/dist/workerd/constants.d.ts.map +1 -1
- package/dist/workerd/constants.js +1 -1
- package/dist/workerd/constants.js.map +1 -1
- package/dist/workerd/credentials/chainedTokenCredential.d.ts +1 -1
- package/dist/workerd/credentials/chainedTokenCredential.js +1 -1
- package/dist/workerd/credentials/chainedTokenCredential.js.map +1 -1
- package/dist/workerd/credentials/clientCertificateCredential.d.ts.map +1 -1
- package/dist/workerd/credentials/clientCertificateCredential.js +2 -13
- package/dist/workerd/credentials/clientCertificateCredential.js.map +1 -1
- package/dist/workerd/credentials/defaultAzureCredential.d.ts +1 -1
- package/dist/workerd/credentials/defaultAzureCredential.js +1 -1
- package/dist/workerd/credentials/defaultAzureCredential.js.map +1 -1
- package/dist/workerd/credentials/workloadIdentityCredential.d.ts +20 -0
- package/dist/workerd/credentials/workloadIdentityCredential.d.ts.map +1 -1
- package/dist/workerd/credentials/workloadIdentityCredential.js +191 -14
- package/dist/workerd/credentials/workloadIdentityCredential.js.map +1 -1
- package/dist/workerd/credentials/workloadIdentityCredentialOptions.d.ts +4 -0
- package/dist/workerd/credentials/workloadIdentityCredentialOptions.d.ts.map +1 -1
- package/dist/workerd/credentials/workloadIdentityCredentialOptions.js.map +1 -1
- package/dist/workerd/util/certificatesUtils.d.ts +13 -0
- package/dist/workerd/util/certificatesUtils.d.ts.map +1 -0
- package/dist/workerd/util/certificatesUtils.js +47 -0
- package/dist/workerd/util/certificatesUtils.js.map +1 -0
- package/package.json +20 -16
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
// Licensed under the MIT License.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.WorkloadIdentityCredential = exports.SupportedWorkloadEnvironmentVariables = void 0;
|
|
6
|
+
exports.parseAndValidateCustomTokenProxy = parseAndValidateCustomTokenProxy;
|
|
6
7
|
const logging_js_1 = require("../util/logging.js");
|
|
7
8
|
const clientAssertionCredential_js_1 = require("./clientAssertionCredential.js");
|
|
8
9
|
const errors_js_1 = require("../errors.js");
|
|
9
10
|
const tenantIdUtils_js_1 = require("../util/tenantIdUtils.js");
|
|
10
11
|
const promises_1 = require("node:fs/promises");
|
|
12
|
+
const core_rest_pipeline_1 = require("@azure/core-rest-pipeline");
|
|
13
|
+
const certificatesUtils_js_1 = require("../util/certificatesUtils.js");
|
|
14
|
+
const node_fs_1 = require("node:fs");
|
|
11
15
|
const credentialName = "WorkloadIdentityCredential";
|
|
12
16
|
/**
|
|
13
17
|
* Contains the list of all supported environment variable names so that an
|
|
@@ -22,6 +26,65 @@ exports.SupportedWorkloadEnvironmentVariables = [
|
|
|
22
26
|
"AZURE_FEDERATED_TOKEN_FILE",
|
|
23
27
|
];
|
|
24
28
|
const logger = (0, logging_js_1.credentialLogger)(credentialName);
|
|
29
|
+
/**
|
|
30
|
+
* Error messages for WorkloadIdentityCredential
|
|
31
|
+
*/
|
|
32
|
+
const ErrorMessages = {
|
|
33
|
+
FAILED_TO_PARSE_TOKEN_PROXY: (endpoint, error) => `Failed to parse custom token proxy URL "${endpoint}": ${error}`,
|
|
34
|
+
INVALID_HTTPS_SCHEME: (protocol) => `Custom token endpoint must use https scheme, got "${protocol}"`,
|
|
35
|
+
TOKEN_ENDPOINT_NO_USER_INFO: (url) => `Custom token endpoint URL "${url}" must not contain user info`,
|
|
36
|
+
TOKEN_ENDPOINT_NO_QUERY: (url) => `Custom token endpoint URL "${url}" must not contain a query`,
|
|
37
|
+
TOKEN_ENDPOINT_NO_FRAGMENT: (url) => `Custom token endpoint URL "${url}" must not contain a fragment`,
|
|
38
|
+
CA_FILE_EMPTY: (file) => `CA certificate file is empty: ${file}`,
|
|
39
|
+
FAILED_TO_READ_CA_FILE: (file, error) => `Failed to read CA certificate file: ${file}. ${error}`,
|
|
40
|
+
INVALID_CA_CERTIFICATES: `Invalid CA certificate data: no valid PEM certificates found`,
|
|
41
|
+
INVALID_FILE_PATH: (path) => `Invalid file path provided ${path}.`,
|
|
42
|
+
NO_FILE_CONTENT: (path) => `No content on the file ${path}.`,
|
|
43
|
+
NO_CA_SOURCE: `No CA certificate source specified.`,
|
|
44
|
+
CLIENT_ID_REQUIRED: `clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_CLIENT_ID".
|
|
45
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
|
|
46
|
+
TENANT_ID_REQUIRED: `tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_TENANT_ID".
|
|
47
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
|
|
48
|
+
TOKEN_FILE_PATH_REQUIRED: `federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - "AZURE_FEDERATED_TOKEN_FILE".
|
|
49
|
+
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
|
|
50
|
+
TOKEN_PROXY_NOT_SET: `AZURE_KUBERNETES_TOKEN_PROXY is not set but other custom endpoint-related environment variables are present`,
|
|
51
|
+
CA_FILE_AND_DATA_EXCLUSIVE: `AZURE_KUBERNETES_CA_FILE and AZURE_KUBERNETES_CA_DATA are mutually exclusive. Specify only one.`,
|
|
52
|
+
MISSING_ENV_VARS: `tenantId, clientId, and federatedTokenFilePath are required parameters.
|
|
53
|
+
In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
|
|
54
|
+
"AZURE_TENANT_ID",
|
|
55
|
+
"AZURE_CLIENT_ID",
|
|
56
|
+
"AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* @internal
|
|
60
|
+
* Parses and validates the custom token proxy endpoint URL
|
|
61
|
+
*/
|
|
62
|
+
function parseAndValidateCustomTokenProxy(endpoint) {
|
|
63
|
+
let tokenProxy;
|
|
64
|
+
try {
|
|
65
|
+
tokenProxy = new URL(endpoint);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_PARSE_TOKEN_PROXY(endpoint, error)}`);
|
|
69
|
+
}
|
|
70
|
+
if (tokenProxy.protocol !== "https:") {
|
|
71
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_HTTPS_SCHEME(tokenProxy.protocol)}`);
|
|
72
|
+
}
|
|
73
|
+
if (tokenProxy.username || tokenProxy.password) {
|
|
74
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_USER_INFO(tokenProxy.toString())}`);
|
|
75
|
+
}
|
|
76
|
+
if (tokenProxy.search) {
|
|
77
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_QUERY(tokenProxy.toString())}`);
|
|
78
|
+
}
|
|
79
|
+
if (tokenProxy.hash) {
|
|
80
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_FRAGMENT(tokenProxy.toString())}`);
|
|
81
|
+
}
|
|
82
|
+
if (!tokenProxy.pathname || tokenProxy.pathname === "") {
|
|
83
|
+
// if the path is empty, set it to "/" to avoid stripping the path from req.URL
|
|
84
|
+
tokenProxy.pathname = "/";
|
|
85
|
+
}
|
|
86
|
+
return tokenProxy.toString();
|
|
87
|
+
}
|
|
25
88
|
/**
|
|
26
89
|
* Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)
|
|
27
90
|
* to access other Azure resources without the need for a service principal or managed identity. With Workload Identity
|
|
@@ -41,6 +104,12 @@ class WorkloadIdentityCredential {
|
|
|
41
104
|
azureFederatedTokenFileContent = undefined;
|
|
42
105
|
cacheDate = undefined;
|
|
43
106
|
federatedTokenFilePath;
|
|
107
|
+
// AKS proxy CA caching - persists across token requests
|
|
108
|
+
cachedTlsSettings;
|
|
109
|
+
cachedCaData;
|
|
110
|
+
caData;
|
|
111
|
+
caFile;
|
|
112
|
+
sniName;
|
|
44
113
|
/**
|
|
45
114
|
* WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.
|
|
46
115
|
*
|
|
@@ -59,19 +128,132 @@ class WorkloadIdentityCredential {
|
|
|
59
128
|
(0, tenantIdUtils_js_1.checkTenantId)(logger, tenantId);
|
|
60
129
|
}
|
|
61
130
|
if (!clientId) {
|
|
62
|
-
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable.
|
|
63
|
-
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
|
|
131
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CLIENT_ID_REQUIRED}`);
|
|
64
132
|
}
|
|
65
133
|
if (!tenantId) {
|
|
66
|
-
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable.
|
|
67
|
-
See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`);
|
|
134
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TENANT_ID_REQUIRED}`);
|
|
68
135
|
}
|
|
69
136
|
if (!this.federatedTokenFilePath) {
|
|
70
|
-
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable.
|
|
71
|
-
|
|
137
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_FILE_PATH_REQUIRED}`);
|
|
138
|
+
}
|
|
139
|
+
// Use identity binding mode only when enableAzureKubernetesTokenProxy is set
|
|
140
|
+
if (workloadIdentityCredentialOptions.enableAzureKubernetesTokenProxy) {
|
|
141
|
+
const kubernetesTokenProxy = process.env.AZURE_KUBERNETES_TOKEN_PROXY;
|
|
142
|
+
const kubernetesSNIName = process.env.AZURE_KUBERNETES_SNI_NAME;
|
|
143
|
+
const kubernetesCAFile = process.env.AZURE_KUBERNETES_CA_FILE;
|
|
144
|
+
const kubernetesCAData = process.env.AZURE_KUBERNETES_CA_DATA;
|
|
145
|
+
if (!kubernetesTokenProxy) {
|
|
146
|
+
// Custom token proxy is not set, while other Kubernetes-related environment variables are present,
|
|
147
|
+
// this is likely a configuration issue so erroring out to avoid misconfiguration
|
|
148
|
+
if (kubernetesSNIName || kubernetesCAFile || kubernetesCAData) {
|
|
149
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.TOKEN_PROXY_NOT_SET}`);
|
|
150
|
+
}
|
|
151
|
+
logger.info(`enableAzureKubernetesTokenProxy is true but AZURE_KUBERNETES_TOKEN_PROXY is not set, using normal authentication flow`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const tokenProxy = parseAndValidateCustomTokenProxy(kubernetesTokenProxy);
|
|
155
|
+
// CAFile and CAData are mutually exclusive, at most one can be set.
|
|
156
|
+
// If none of CAFile or CAData are set, the default system CA pool will be used.
|
|
157
|
+
if (kubernetesCAFile && kubernetesCAData) {
|
|
158
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_AND_DATA_EXCLUSIVE}`);
|
|
159
|
+
}
|
|
160
|
+
this.caData = kubernetesCAData;
|
|
161
|
+
this.caFile = kubernetesCAFile;
|
|
162
|
+
this.sniName = kubernetesSNIName;
|
|
163
|
+
// Configure client options with AKS proxy client
|
|
164
|
+
const proxyClient = this.createAksProxyClient(tokenProxy);
|
|
165
|
+
workloadIdentityCredentialOptions.httpClient = proxyClient;
|
|
166
|
+
logger.info(`${credentialName}: Using proxy client for token requests`);
|
|
167
|
+
}
|
|
72
168
|
}
|
|
73
169
|
logger.info(`Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`);
|
|
74
|
-
this.client = new clientAssertionCredential_js_1.ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this),
|
|
170
|
+
this.client = new clientAssertionCredential_js_1.ClientAssertionCredential(tenantId, clientId, this.readFileContents.bind(this), workloadIdentityCredentialOptions);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Creates a proxy HttpClient that intercepts token requests and redirects them to the Kubernetes endpoint
|
|
174
|
+
* Caching is handled at the credential level to persist across token requests
|
|
175
|
+
*/
|
|
176
|
+
createAksProxyClient(tokenEndpoint) {
|
|
177
|
+
const defaultClient = (0, core_rest_pipeline_1.createDefaultHttpClient)();
|
|
178
|
+
// Init cached TLS settings at construction time to fail fast on misconfiguration
|
|
179
|
+
this.cachedTlsSettings = this.getTlsSettings();
|
|
180
|
+
return {
|
|
181
|
+
sendRequest: async (request) => {
|
|
182
|
+
const requestUrl = new URL(request.url);
|
|
183
|
+
logger.info(`${credentialName}: Redirecting request to Kubernetes endpoint: ${tokenEndpoint}`);
|
|
184
|
+
const proxyUrl = new URL(tokenEndpoint);
|
|
185
|
+
// Remove leading slash from request path and join with proxy path
|
|
186
|
+
const requestPath = requestUrl.pathname.replace(/^\//, "");
|
|
187
|
+
const combinedPath = proxyUrl.pathname.endsWith("/")
|
|
188
|
+
? proxyUrl.pathname + requestPath
|
|
189
|
+
: proxyUrl.pathname + "/" + requestPath;
|
|
190
|
+
// Create new URL preserving query and fragment from original request
|
|
191
|
+
const newUrl = new URL(proxyUrl.origin);
|
|
192
|
+
newUrl.pathname = combinedPath;
|
|
193
|
+
newUrl.search = requestUrl.search;
|
|
194
|
+
newUrl.hash = requestUrl.hash;
|
|
195
|
+
request.url = newUrl.toString();
|
|
196
|
+
request.tlsSettings = this.getTlsSettings();
|
|
197
|
+
logger.info(`${credentialName}: Sending request to ${request.url}`);
|
|
198
|
+
// Forward the modified request with custom TLS settings
|
|
199
|
+
return defaultClient.sendRequest(request);
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Gets TLS settings for the request.
|
|
205
|
+
* Handles a few scenarios with CA data or CA file provided.
|
|
206
|
+
*/
|
|
207
|
+
getTlsSettings() {
|
|
208
|
+
// No CA overrides, use default transport
|
|
209
|
+
if (!this.caData && !this.caFile) {
|
|
210
|
+
if (!this.cachedTlsSettings) {
|
|
211
|
+
this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};
|
|
212
|
+
}
|
|
213
|
+
return this.cachedTlsSettings;
|
|
214
|
+
}
|
|
215
|
+
// Host provided CA bytes in AZURE_KUBERNETES_CA_DATA and can't change now
|
|
216
|
+
if (!this.caFile) {
|
|
217
|
+
if (!this.cachedTlsSettings) {
|
|
218
|
+
if (!(0, certificatesUtils_js_1.canParseAsX509Certificate)(this.caData)) {
|
|
219
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`);
|
|
220
|
+
}
|
|
221
|
+
this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};
|
|
222
|
+
this.cachedTlsSettings.ca = this.caData;
|
|
223
|
+
}
|
|
224
|
+
return this.cachedTlsSettings;
|
|
225
|
+
}
|
|
226
|
+
// Host provided the CA bytes in a file whose contents it can change,
|
|
227
|
+
let fileContent;
|
|
228
|
+
try {
|
|
229
|
+
fileContent = (0, node_fs_1.readFileSync)(this.caFile);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_READ_CA_FILE(this.caFile, error)}`);
|
|
233
|
+
}
|
|
234
|
+
// This can happen in the middle of CA rotation
|
|
235
|
+
if (fileContent.length === 0) {
|
|
236
|
+
if (!this.cachedTlsSettings) {
|
|
237
|
+
// If the transport was never created, error out here to force retrying the call later
|
|
238
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_EMPTY(this.caFile)}`);
|
|
239
|
+
}
|
|
240
|
+
// If the transport was already created, just keep using it
|
|
241
|
+
return this.cachedTlsSettings;
|
|
242
|
+
}
|
|
243
|
+
// Check if CA has changed
|
|
244
|
+
if (!this.cachedCaData || !fileContent.equals(this.cachedCaData)) {
|
|
245
|
+
const caDataString = fileContent.toString("utf8");
|
|
246
|
+
if (!(0, certificatesUtils_js_1.canParseAsX509Certificate)(caDataString)) {
|
|
247
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`);
|
|
248
|
+
}
|
|
249
|
+
// CA has changed, rebuild the TLS settings with new CA pool
|
|
250
|
+
this.cachedTlsSettings = {
|
|
251
|
+
ca: caDataString,
|
|
252
|
+
...(this.sniName && { servername: this.sniName }),
|
|
253
|
+
};
|
|
254
|
+
this.cachedCaData = fileContent;
|
|
255
|
+
}
|
|
256
|
+
return this.cachedTlsSettings;
|
|
75
257
|
}
|
|
76
258
|
/**
|
|
77
259
|
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
|
@@ -83,11 +265,7 @@ class WorkloadIdentityCredential {
|
|
|
83
265
|
*/
|
|
84
266
|
async getToken(scopes, options) {
|
|
85
267
|
if (!this.client) {
|
|
86
|
-
const errorMessage = `${credentialName}: is unavailable.
|
|
87
|
-
In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables -
|
|
88
|
-
"AZURE_TENANT_ID",
|
|
89
|
-
"AZURE_CLIENT_ID",
|
|
90
|
-
"AZURE_FEDERATED_TOKEN_FILE". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;
|
|
268
|
+
const errorMessage = `${credentialName}: is unavailable. ${ErrorMessages.MISSING_ENV_VARS}`;
|
|
91
269
|
logger.info(errorMessage);
|
|
92
270
|
throw new errors_js_1.CredentialUnavailableError(errorMessage);
|
|
93
271
|
}
|
|
@@ -100,13 +278,13 @@ class WorkloadIdentityCredential {
|
|
|
100
278
|
this.azureFederatedTokenFileContent = undefined;
|
|
101
279
|
}
|
|
102
280
|
if (!this.federatedTokenFilePath) {
|
|
103
|
-
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable.
|
|
281
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.INVALID_FILE_PATH(this.federatedTokenFilePath)}`);
|
|
104
282
|
}
|
|
105
283
|
if (!this.azureFederatedTokenFileContent) {
|
|
106
284
|
const file = await (0, promises_1.readFile)(this.federatedTokenFilePath, "utf8");
|
|
107
285
|
const value = file.trim();
|
|
108
286
|
if (!value) {
|
|
109
|
-
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable.
|
|
287
|
+
throw new errors_js_1.CredentialUnavailableError(`${credentialName}: is unavailable. ${ErrorMessages.NO_FILE_CONTENT(this.federatedTokenFilePath)}`);
|
|
110
288
|
}
|
|
111
289
|
else {
|
|
112
290
|
this.azureFederatedTokenFileContent = value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workloadIdentityCredential.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport { credentialLogger, processEnvVars } from \"../util/logging.js\";\n\nimport { ClientAssertionCredential } from \"./clientAssertionCredential.js\";\nimport { CredentialUnavailableError } from \"../errors.js\";\nimport type { WorkloadIdentityCredentialOptions } from \"./workloadIdentityCredentialOptions.js\";\nimport { checkTenantId } from \"../util/tenantIdUtils.js\";\nimport { readFile } from \"node:fs/promises\";\n\nconst credentialName = \"WorkloadIdentityCredential\";\n/**\n * Contains the list of all supported environment variable names so that an\n * appropriate error message can be generated when no credentials can be\n * configured.\n *\n * @internal\n */\nexport const SupportedWorkloadEnvironmentVariables = [\n \"AZURE_TENANT_ID\",\n \"AZURE_CLIENT_ID\",\n \"AZURE_FEDERATED_TOKEN_FILE\",\n];\nconst logger = credentialLogger(credentialName);\n/**\n * Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)\n * to access other Azure resources without the need for a service principal or managed identity. With Workload Identity\n * authentication, applications authenticate themselves using their own identity, rather than using a shared service\n * principal or managed identity. Under the hood, Workload Identity authentication uses the concept of Service Account\n * Credentials (SACs), which are automatically created by Azure and stored securely in the VM. By using Workload\n * Identity authentication, you can avoid the need to manage and rotate service principals or managed identities for\n * each application on each VM. Additionally, because SACs are created automatically and managed by Azure, you don't\n * need to worry about storing and securing sensitive credentials themselves.\n * The WorkloadIdentityCredential supports Microsoft Entra Workload ID authentication on Azure Kubernetes and acquires\n * a token using the SACs available in the Azure Kubernetes environment.\n * Refer to <a href=\"https://learn.microsoft.com/azure/aks/workload-identity-overview\">Microsoft Entra\n * Workload ID</a> for more information.\n */\nexport class WorkloadIdentityCredential implements TokenCredential {\n private client: ClientAssertionCredential | undefined;\n private azureFederatedTokenFileContent: string | undefined = undefined;\n private cacheDate: number | undefined = undefined;\n private federatedTokenFilePath: string | undefined;\n\n /**\n * WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.\n *\n * @param options - The identity client options to use for authentication.\n */\n constructor(options?: WorkloadIdentityCredentialOptions) {\n // Logging environment variables for error details\n const assignedEnv = processEnvVars(SupportedWorkloadEnvironmentVariables).assigned.join(\", \");\n logger.info(`Found the following environment variables: ${assignedEnv}`);\n\n const workloadIdentityCredentialOptions = options ?? {};\n const tenantId = workloadIdentityCredentialOptions.tenantId || process.env.AZURE_TENANT_ID;\n const clientId = workloadIdentityCredentialOptions.clientId || process.env.AZURE_CLIENT_ID;\n this.federatedTokenFilePath =\n workloadIdentityCredentialOptions.tokenFilePath || process.env.AZURE_FEDERATED_TOKEN_FILE;\n if (tenantId) {\n checkTenantId(logger, tenantId);\n }\n if (!clientId) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_CLIENT_ID\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n );\n }\n\n if (!tenantId) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_TENANT_ID\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n );\n }\n\n if (!this.federatedTokenFilePath) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_FEDERATED_TOKEN_FILE\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n );\n }\n\n logger.info(\n `Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`,\n );\n this.client = new ClientAssertionCredential(\n tenantId,\n clientId,\n this.readFileContents.bind(this),\n options,\n );\n }\n\n /**\n * Authenticates with Microsoft Entra ID and returns an access token if successful.\n * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.\n *\n * @param scopes - The list of scopes for which the token will have access.\n * @param options - The options used to configure any requests this\n * TokenCredential implementation might make.\n */\n public async getToken(\n scopes: string | string[],\n options?: GetTokenOptions,\n ): Promise<AccessToken> {\n if (!this.client) {\n const errorMessage = `${credentialName}: is unavailable. tenantId, clientId, and federatedTokenFilePath are required parameters. \n In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables - \n \"AZURE_TENANT_ID\",\n \"AZURE_CLIENT_ID\",\n \"AZURE_FEDERATED_TOKEN_FILE\". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`;\n logger.info(errorMessage);\n throw new CredentialUnavailableError(errorMessage);\n }\n logger.info(\"Invoking getToken() of Client Assertion Credential\");\n return this.client.getToken(scopes, options);\n }\n\n private async readFileContents(): Promise<string> {\n // Cached assertions expire after 5 minutes\n if (this.cacheDate !== undefined && Date.now() - this.cacheDate >= 1000 * 60 * 5) {\n this.azureFederatedTokenFileContent = undefined;\n }\n if (!this.federatedTokenFilePath) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. Invalid file path provided ${this.federatedTokenFilePath}.`,\n );\n }\n if (!this.azureFederatedTokenFileContent) {\n const file = await readFile(this.federatedTokenFilePath, \"utf8\");\n const value = file.trim();\n if (!value) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. No content on the file ${this.federatedTokenFilePath}.`,\n );\n } else {\n this.azureFederatedTokenFileContent = value;\n this.cacheDate = Date.now();\n }\n }\n return this.azureFederatedTokenFileContent;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workloadIdentityCredential.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport { credentialLogger, processEnvVars } from \"../util/logging.js\";\n\nimport { ClientAssertionCredential } from \"./clientAssertionCredential.js\";\nimport { CredentialUnavailableError } from \"../errors.js\";\nimport type { WorkloadIdentityCredentialOptions } from \"./workloadIdentityCredentialOptions.js\";\nimport { checkTenantId } from \"../util/tenantIdUtils.js\";\nimport { readFile } from \"node:fs/promises\";\nimport type { PipelineRequest, PipelineResponse, HttpClient } from \"@azure/core-rest-pipeline\";\nimport { createDefaultHttpClient } from \"@azure/core-rest-pipeline\";\nimport type { TlsSettings } from \"@azure/core-rest-pipeline\";\nimport { canParseAsX509Certificate } from \"../util/certificatesUtils.js\";\nimport { readFileSync } from \"node:fs\";\n\nconst credentialName = \"WorkloadIdentityCredential\";\n/**\n * Contains the list of all supported environment variable names so that an\n * appropriate error message can be generated when no credentials can be\n * configured.\n *\n * @internal\n */\nexport const SupportedWorkloadEnvironmentVariables = [\n \"AZURE_TENANT_ID\",\n \"AZURE_CLIENT_ID\",\n \"AZURE_FEDERATED_TOKEN_FILE\",\n];\n\nconst logger = credentialLogger(credentialName);\n\n/**\n * Error messages for WorkloadIdentityCredential\n */\nconst ErrorMessages = {\n FAILED_TO_PARSE_TOKEN_PROXY: (endpoint: string, error: unknown) =>\n `Failed to parse custom token proxy URL \"${endpoint}\": ${error}`,\n INVALID_HTTPS_SCHEME: (protocol: string) =>\n `Custom token endpoint must use https scheme, got \"${protocol}\"`,\n TOKEN_ENDPOINT_NO_USER_INFO: (url: string) =>\n `Custom token endpoint URL \"${url}\" must not contain user info`,\n TOKEN_ENDPOINT_NO_QUERY: (url: string) =>\n `Custom token endpoint URL \"${url}\" must not contain a query`,\n TOKEN_ENDPOINT_NO_FRAGMENT: (url: string) =>\n `Custom token endpoint URL \"${url}\" must not contain a fragment`,\n CA_FILE_EMPTY: (file: string) => `CA certificate file is empty: ${file}`,\n FAILED_TO_READ_CA_FILE: (file: string, error: unknown) =>\n `Failed to read CA certificate file: ${file}. ${error}`,\n INVALID_CA_CERTIFICATES: `Invalid CA certificate data: no valid PEM certificates found`,\n INVALID_FILE_PATH: (path: string | undefined) => `Invalid file path provided ${path}.`,\n NO_FILE_CONTENT: (path: string) => `No content on the file ${path}.`,\n NO_CA_SOURCE: `No CA certificate source specified.`,\n CLIENT_ID_REQUIRED: `clientId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_CLIENT_ID\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n TENANT_ID_REQUIRED: `tenantId is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_TENANT_ID\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n TOKEN_FILE_PATH_REQUIRED: `federatedTokenFilePath is a required parameter. In DefaultAzureCredential and ManagedIdentityCredential, this can be provided as an environment variable - \"AZURE_FEDERATED_TOKEN_FILE\".\n See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n TOKEN_PROXY_NOT_SET: `AZURE_KUBERNETES_TOKEN_PROXY is not set but other custom endpoint-related environment variables are present`,\n CA_FILE_AND_DATA_EXCLUSIVE: `AZURE_KUBERNETES_CA_FILE and AZURE_KUBERNETES_CA_DATA are mutually exclusive. Specify only one.`,\n MISSING_ENV_VARS: `tenantId, clientId, and federatedTokenFilePath are required parameters. \n In DefaultAzureCredential and ManagedIdentityCredential, these can be provided as environment variables - \n \"AZURE_TENANT_ID\",\n \"AZURE_CLIENT_ID\",\n \"AZURE_FEDERATED_TOKEN_FILE\". See the troubleshooting guide for more information: https://aka.ms/azsdk/js/identity/workloadidentitycredential/troubleshoot`,\n};\n\n/**\n * @internal\n * Parses and validates the custom token proxy endpoint URL\n */\nexport function parseAndValidateCustomTokenProxy(endpoint: string): string {\n let tokenProxy: URL;\n try {\n tokenProxy = new URL(endpoint);\n } catch (error) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_PARSE_TOKEN_PROXY(endpoint, error)}`,\n );\n }\n\n if (tokenProxy.protocol !== \"https:\") {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.INVALID_HTTPS_SCHEME(tokenProxy.protocol)}`,\n );\n }\n\n if (tokenProxy.username || tokenProxy.password) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_USER_INFO(tokenProxy.toString())}`,\n );\n }\n\n if (tokenProxy.search) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_QUERY(tokenProxy.toString())}`,\n );\n }\n\n if (tokenProxy.hash) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_ENDPOINT_NO_FRAGMENT(tokenProxy.toString())}`,\n );\n }\n\n if (!tokenProxy.pathname || tokenProxy.pathname === \"\") {\n // if the path is empty, set it to \"/\" to avoid stripping the path from req.URL\n tokenProxy.pathname = \"/\";\n }\n\n return tokenProxy.toString();\n}\n\n/**\n * Workload Identity authentication is a feature in Azure that allows applications running on virtual machines (VMs)\n * to access other Azure resources without the need for a service principal or managed identity. With Workload Identity\n * authentication, applications authenticate themselves using their own identity, rather than using a shared service\n * principal or managed identity. Under the hood, Workload Identity authentication uses the concept of Service Account\n * Credentials (SACs), which are automatically created by Azure and stored securely in the VM. By using Workload\n * Identity authentication, you can avoid the need to manage and rotate service principals or managed identities for\n * each application on each VM. Additionally, because SACs are created automatically and managed by Azure, you don't\n * need to worry about storing and securing sensitive credentials themselves.\n * The WorkloadIdentityCredential supports Microsoft Entra Workload ID authentication on Azure Kubernetes and acquires\n * a token using the SACs available in the Azure Kubernetes environment.\n * Refer to <a href=\"https://learn.microsoft.com/azure/aks/workload-identity-overview\">Microsoft Entra\n * Workload ID</a> for more information.\n */\nexport class WorkloadIdentityCredential implements TokenCredential {\n private client: ClientAssertionCredential | undefined;\n private azureFederatedTokenFileContent: string | undefined = undefined;\n private cacheDate: number | undefined = undefined;\n private federatedTokenFilePath: string | undefined;\n\n // AKS proxy CA caching - persists across token requests\n private cachedTlsSettings: (TlsSettings & { servername?: string }) | undefined;\n private cachedCaData: Buffer | undefined;\n private caData: string | undefined;\n private caFile: string | undefined;\n private sniName: string | undefined;\n\n /**\n * WorkloadIdentityCredential supports Microsoft Entra Workload ID on Kubernetes.\n *\n * @param options - The identity client options to use for authentication.\n */\n constructor(options?: WorkloadIdentityCredentialOptions) {\n // Logging environment variables for error details\n const assignedEnv = processEnvVars(SupportedWorkloadEnvironmentVariables).assigned.join(\", \");\n logger.info(`Found the following environment variables: ${assignedEnv}`);\n\n const workloadIdentityCredentialOptions = options ?? {};\n const tenantId = workloadIdentityCredentialOptions.tenantId || process.env.AZURE_TENANT_ID;\n const clientId = workloadIdentityCredentialOptions.clientId || process.env.AZURE_CLIENT_ID;\n this.federatedTokenFilePath =\n workloadIdentityCredentialOptions.tokenFilePath || process.env.AZURE_FEDERATED_TOKEN_FILE;\n\n if (tenantId) {\n checkTenantId(logger, tenantId);\n }\n if (!clientId) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.CLIENT_ID_REQUIRED}`,\n );\n }\n\n if (!tenantId) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TENANT_ID_REQUIRED}`,\n );\n }\n\n if (!this.federatedTokenFilePath) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_FILE_PATH_REQUIRED}`,\n );\n }\n\n // Use identity binding mode only when enableAzureKubernetesTokenProxy is set\n if (workloadIdentityCredentialOptions.enableAzureKubernetesTokenProxy) {\n const kubernetesTokenProxy = process.env.AZURE_KUBERNETES_TOKEN_PROXY;\n const kubernetesSNIName = process.env.AZURE_KUBERNETES_SNI_NAME;\n const kubernetesCAFile = process.env.AZURE_KUBERNETES_CA_FILE;\n const kubernetesCAData = process.env.AZURE_KUBERNETES_CA_DATA;\n\n if (!kubernetesTokenProxy) {\n // Custom token proxy is not set, while other Kubernetes-related environment variables are present,\n // this is likely a configuration issue so erroring out to avoid misconfiguration\n if (kubernetesSNIName || kubernetesCAFile || kubernetesCAData) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.TOKEN_PROXY_NOT_SET}`,\n );\n }\n logger.info(\n `enableAzureKubernetesTokenProxy is true but AZURE_KUBERNETES_TOKEN_PROXY is not set, using normal authentication flow`,\n );\n } else {\n const tokenProxy = parseAndValidateCustomTokenProxy(kubernetesTokenProxy);\n\n // CAFile and CAData are mutually exclusive, at most one can be set.\n // If none of CAFile or CAData are set, the default system CA pool will be used.\n if (kubernetesCAFile && kubernetesCAData) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_AND_DATA_EXCLUSIVE}`,\n );\n }\n\n this.caData = kubernetesCAData;\n this.caFile = kubernetesCAFile;\n this.sniName = kubernetesSNIName;\n\n // Configure client options with AKS proxy client\n const proxyClient = this.createAksProxyClient(tokenProxy);\n workloadIdentityCredentialOptions.httpClient = proxyClient;\n logger.info(`${credentialName}: Using proxy client for token requests`);\n }\n }\n\n logger.info(\n `Invoking ClientAssertionCredential with tenant ID: ${tenantId}, clientId: ${workloadIdentityCredentialOptions.clientId} and federated token path: [REDACTED]`,\n );\n\n this.client = new ClientAssertionCredential(\n tenantId,\n clientId,\n this.readFileContents.bind(this),\n workloadIdentityCredentialOptions,\n );\n }\n\n /**\n * Creates a proxy HttpClient that intercepts token requests and redirects them to the Kubernetes endpoint\n * Caching is handled at the credential level to persist across token requests\n */\n private createAksProxyClient(tokenEndpoint: string): HttpClient {\n const defaultClient = createDefaultHttpClient();\n // Init cached TLS settings at construction time to fail fast on misconfiguration\n this.cachedTlsSettings = this.getTlsSettings();\n\n return {\n sendRequest: async (request: PipelineRequest): Promise<PipelineResponse> => {\n const requestUrl = new URL(request.url);\n\n logger.info(\n `${credentialName}: Redirecting request to Kubernetes endpoint: ${tokenEndpoint}`,\n );\n\n const proxyUrl = new URL(tokenEndpoint);\n\n // Remove leading slash from request path and join with proxy path\n const requestPath = requestUrl.pathname.replace(/^\\//, \"\");\n const combinedPath = proxyUrl.pathname.endsWith(\"/\")\n ? proxyUrl.pathname + requestPath\n : proxyUrl.pathname + \"/\" + requestPath;\n\n // Create new URL preserving query and fragment from original request\n const newUrl = new URL(proxyUrl.origin);\n newUrl.pathname = combinedPath;\n newUrl.search = requestUrl.search;\n newUrl.hash = requestUrl.hash;\n\n request.url = newUrl.toString();\n request.tlsSettings = this.getTlsSettings();\n\n logger.info(`${credentialName}: Sending request to ${request.url}`);\n // Forward the modified request with custom TLS settings\n return defaultClient.sendRequest(request);\n },\n };\n }\n\n /**\n * Gets TLS settings for the request.\n * Handles a few scenarios with CA data or CA file provided.\n */\n private getTlsSettings(): TlsSettings & { servername?: string } {\n // No CA overrides, use default transport\n if (!this.caData && !this.caFile) {\n if (!this.cachedTlsSettings) {\n this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};\n }\n return this.cachedTlsSettings;\n }\n\n // Host provided CA bytes in AZURE_KUBERNETES_CA_DATA and can't change now\n if (!this.caFile) {\n if (!this.cachedTlsSettings) {\n if (!canParseAsX509Certificate(this.caData!)) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`,\n );\n }\n this.cachedTlsSettings = this.sniName ? { servername: this.sniName } : {};\n this.cachedTlsSettings.ca = this.caData;\n }\n return this.cachedTlsSettings;\n }\n\n // Host provided the CA bytes in a file whose contents it can change,\n let fileContent: Buffer;\n try {\n fileContent = readFileSync(this.caFile);\n } catch (error) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.FAILED_TO_READ_CA_FILE(this.caFile!, error)}`,\n );\n }\n // This can happen in the middle of CA rotation\n if (fileContent.length === 0) {\n if (!this.cachedTlsSettings) {\n // If the transport was never created, error out here to force retrying the call later\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.CA_FILE_EMPTY(this.caFile)}`,\n );\n }\n // If the transport was already created, just keep using it\n return this.cachedTlsSettings;\n }\n\n // Check if CA has changed\n if (!this.cachedCaData || !fileContent.equals(this.cachedCaData)) {\n const caDataString = fileContent.toString(\"utf8\");\n\n if (!canParseAsX509Certificate(caDataString)) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.INVALID_CA_CERTIFICATES}`,\n );\n }\n\n // CA has changed, rebuild the TLS settings with new CA pool\n this.cachedTlsSettings = {\n ca: caDataString,\n ...(this.sniName && { servername: this.sniName }),\n };\n this.cachedCaData = fileContent;\n }\n\n return this.cachedTlsSettings!;\n }\n\n /**\n * Authenticates with Microsoft Entra ID and returns an access token if successful.\n * If authentication fails, a {@link CredentialUnavailableError} will be thrown with the details of the failure.\n *\n * @param scopes - The list of scopes for which the token will have access.\n * @param options - The options used to configure any requests this\n * TokenCredential implementation might make.\n */\n public async getToken(\n scopes: string | string[],\n options?: GetTokenOptions,\n ): Promise<AccessToken> {\n if (!this.client) {\n const errorMessage = `${credentialName}: is unavailable. ${ErrorMessages.MISSING_ENV_VARS}`;\n logger.info(errorMessage);\n throw new CredentialUnavailableError(errorMessage);\n }\n logger.info(\"Invoking getToken() of Client Assertion Credential\");\n return this.client.getToken(scopes, options);\n }\n\n private async readFileContents(): Promise<string> {\n // Cached assertions expire after 5 minutes\n if (this.cacheDate !== undefined && Date.now() - this.cacheDate >= 1000 * 60 * 5) {\n this.azureFederatedTokenFileContent = undefined;\n }\n if (!this.federatedTokenFilePath) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.INVALID_FILE_PATH(this.federatedTokenFilePath)}`,\n );\n }\n if (!this.azureFederatedTokenFileContent) {\n const file = await readFile(this.federatedTokenFilePath, \"utf8\");\n const value = file.trim();\n if (!value) {\n throw new CredentialUnavailableError(\n `${credentialName}: is unavailable. ${ErrorMessages.NO_FILE_CONTENT(this.federatedTokenFilePath)}`,\n );\n } else {\n this.azureFederatedTokenFileContent = value;\n this.cacheDate = Date.now();\n }\n }\n return this.azureFederatedTokenFileContent;\n }\n}\n"]}
|
|
@@ -16,5 +16,9 @@ export interface WorkloadIdentityCredentialOptions extends MultiTenantTokenCrede
|
|
|
16
16
|
* The path to a file containing a Kubernetes service account token that authenticates the identity.
|
|
17
17
|
*/
|
|
18
18
|
tokenFilePath?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Enables the identity binding feature.
|
|
21
|
+
*/
|
|
22
|
+
enableAzureKubernetesTokenProxy?: boolean;
|
|
19
23
|
}
|
|
20
24
|
//# sourceMappingURL=workloadIdentityCredentialOptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workloadIdentityCredentialOptions.d.ts","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredentialOptions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,wCAAwC,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,iCACf,SAAQ,iCAAiC,EACvC,0BAA0B;IAC5B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"workloadIdentityCredentialOptions.d.ts","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredentialOptions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,wCAAwC,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,iCACf,SAAQ,iCAAiC,EACvC,0BAA0B;IAC5B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,+BAA+B,CAAC,EAAE,OAAO,CAAC;CAC3C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workloadIdentityCredentialOptions.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredentialOptions.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AuthorityValidationOptions } from \"./authorityValidationOptions.js\";\nimport type { MultiTenantTokenCredentialOptions } from \"./multiTenantTokenCredentialOptions.js\";\n\n/**\n * Options for the {@link WorkloadIdentityCredential}\n */\nexport interface WorkloadIdentityCredentialOptions\n extends MultiTenantTokenCredentialOptions,\n AuthorityValidationOptions {\n /**\n * ID of the application's Microsoft Entra tenant. Also called its directory ID.\n */\n tenantId?: string;\n /**\n * The client ID of a Microsoft Entra app registration.\n */\n clientId?: string;\n /**\n * The path to a file containing a Kubernetes service account token that authenticates the identity.\n */\n tokenFilePath?: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workloadIdentityCredentialOptions.js","sourceRoot":"","sources":["../../../src/credentials/workloadIdentityCredentialOptions.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AuthorityValidationOptions } from \"./authorityValidationOptions.js\";\nimport type { MultiTenantTokenCredentialOptions } from \"./multiTenantTokenCredentialOptions.js\";\n\n/**\n * Options for the {@link WorkloadIdentityCredential}\n */\nexport interface WorkloadIdentityCredentialOptions\n extends MultiTenantTokenCredentialOptions,\n AuthorityValidationOptions {\n /**\n * ID of the application's Microsoft Entra tenant. Also called its directory ID.\n */\n tenantId?: string;\n /**\n * The client ID of a Microsoft Entra app registration.\n */\n clientId?: string;\n /**\n * The path to a file containing a Kubernetes service account token that authenticates the identity.\n */\n tokenFilePath?: string;\n /**\n * Enables the identity binding feature.\n */\n enableAzureKubernetesTokenProxy?: boolean;\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts public keys from PEM certificate content
|
|
3
|
+
* @param pemData - The PEM certificate data to parse
|
|
4
|
+
* @returns Array of base64-encoded public key strings
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractPemCertificateKeys(pemContent: string): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Checks if PEM certificate content can be parsed as X509Certificate
|
|
9
|
+
* @param pemCert - The PEM certificate
|
|
10
|
+
* @returns true if all certificates in the PEM content can be parsed without error
|
|
11
|
+
*/
|
|
12
|
+
export declare function canParseAsX509Certificate(pemCert: string): boolean;
|
|
13
|
+
//# sourceMappingURL=certificatesUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certificatesUtils.d.ts","sourceRoot":"","sources":["../../../src/util/certificatesUtils.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBtE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAgBlE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.extractPemCertificateKeys = extractPemCertificateKeys;
|
|
6
|
+
exports.canParseAsX509Certificate = canParseAsX509Certificate;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
/**
|
|
9
|
+
* Extracts public keys from PEM certificate content
|
|
10
|
+
* @param pemData - The PEM certificate data to parse
|
|
11
|
+
* @returns Array of base64-encoded public key strings
|
|
12
|
+
*/
|
|
13
|
+
function extractPemCertificateKeys(pemContent) {
|
|
14
|
+
const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g;
|
|
15
|
+
const publicKeys = [];
|
|
16
|
+
// Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
|
|
17
|
+
let match;
|
|
18
|
+
do {
|
|
19
|
+
match = certificatePattern.exec(pemContent);
|
|
20
|
+
if (match) {
|
|
21
|
+
publicKeys.push(match[3]);
|
|
22
|
+
}
|
|
23
|
+
} while (match);
|
|
24
|
+
if (publicKeys.length === 0) {
|
|
25
|
+
throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
|
|
26
|
+
}
|
|
27
|
+
return publicKeys;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Checks if PEM certificate content can be parsed as X509Certificate
|
|
31
|
+
* @param pemCert - The PEM certificate
|
|
32
|
+
* @returns true if all certificates in the PEM content can be parsed without error
|
|
33
|
+
*/
|
|
34
|
+
function canParseAsX509Certificate(pemCert) {
|
|
35
|
+
try {
|
|
36
|
+
const pemContents = extractPemCertificateKeys(pemCert);
|
|
37
|
+
for (let i = 0; i < pemContents.length; i++) {
|
|
38
|
+
const pemContent = pemContents[i];
|
|
39
|
+
// Reconstruct the full PEM format for X509Certificate constructor
|
|
40
|
+
const fullPemCertificate = `-----BEGIN CERTIFICATE-----\n${pemContent}\n-----END CERTIFICATE-----`;
|
|
41
|
+
// Attempt to parse as X.509 certificate
|
|
42
|
+
new crypto_1.X509Certificate(fullPemCertificate);
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
catch (extractError) {
|
|
47
|
+
// Return false for any error (extraction or parsing)
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=certificatesUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certificatesUtils.js","sourceRoot":"","sources":["../../../src/util/certificatesUtils.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;AASlC,8DAmBC;AAOD,8DAgBC;AAjDD,mCAAyC;AAEzC;;;;GAIG;AACH,SAAgB,yBAAyB,CAAC,UAAkB;IAC1D,MAAM,kBAAkB,GACtB,+FAA+F,CAAC;IAClG,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,qHAAqH;IACrH,IAAI,KAAK,CAAC;IACV,GAAG,CAAC;QACF,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,KAAK,EAAE,CAAC;YACV,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,QAAQ,KAAK,EAAE;IAEhB,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,SAAgB,yBAAyB,CAAC,OAAe;IACvD,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAEvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAClC,kEAAkE;YAClE,MAAM,kBAAkB,GAAG,gCAAgC,UAAU,6BAA6B,CAAC;YACnG,wCAAwC;YACxC,IAAI,wBAAe,CAAC,kBAAkB,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,YAAY,EAAE,CAAC;QACtB,qDAAqD;QACrD,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { X509Certificate } from \"crypto\";\n\n/**\n * Extracts public keys from PEM certificate content\n * @param pemData - The PEM certificate data to parse\n * @returns Array of base64-encoded public key strings\n */\nexport function extractPemCertificateKeys(pemContent: string): string[] {\n const certificatePattern =\n /(-+BEGIN CERTIFICATE-+)(\\n\\r?|\\r\\n?)([A-Za-z0-9+/\\n\\r]+=*)(\\n\\r?|\\r\\n?)(-+END CERTIFICATE-+)/g;\n const publicKeys: string[] = [];\n\n // Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c\n let match;\n do {\n match = certificatePattern.exec(pemContent);\n if (match) {\n publicKeys.push(match[3]);\n }\n } while (match);\n\n if (publicKeys.length === 0) {\n throw new Error(\"The file at the specified path does not contain a PEM-encoded certificate.\");\n }\n\n return publicKeys;\n}\n\n/**\n * Checks if PEM certificate content can be parsed as X509Certificate\n * @param pemCert - The PEM certificate\n * @returns true if all certificates in the PEM content can be parsed without error\n */\nexport function canParseAsX509Certificate(pemCert: string): boolean {\n try {\n const pemContents = extractPemCertificateKeys(pemCert);\n\n for (let i = 0; i < pemContents.length; i++) {\n const pemContent = pemContents[i];\n // Reconstruct the full PEM format for X509Certificate constructor\n const fullPemCertificate = `-----BEGIN CERTIFICATE-----\\n${pemContent}\\n-----END CERTIFICATE-----`;\n // Attempt to parse as X.509 certificate\n new X509Certificate(fullPemCertificate);\n }\n return true;\n } catch (extractError) {\n // Return false for any error (extraction or parsing)\n return false;\n }\n}\n"]}
|
package/dist/esm/constants.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C;;;GAGG;AAIH,eAAO,MAAM,uBAAuB,yCAAyC,CAAC;AAE9E;;;GAGG;AACH,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC;;GAEG;AACH,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,UAAU,mCAAmC;IAC7C;;;;;SAKK;IACL,YAAY,qCAAqC;IACjD;;OAEG;IACH,eAAe,qCAAqC;IACpD;;OAEG;IACH,gBAAgB,sCAAsC;CACvD;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,uCAAuC,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,EAAU,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,eAAe,CAAC"}
|
package/dist/esm/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAC;AAE3C;;;GAGG;AACH,2EAA2E;AAC3E,6CAA6C;AAC7C,uGAAuG;AACvG,MAAM,CAAC,MAAM,uBAAuB,GAAG,sCAAsC,CAAC;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;AAExC;;GAEG;AACH,MAAM,CAAN,IAAY,mBAoBX;AApBD,WAAY,mBAAmB;IAC7B;;OAEG;IACH,oEAA6C,CAAA;IAC7C;;;;;SAKK;IACL,wEAAiD,CAAA;IACjD;;OAEG;IACH,2EAAoD,CAAA;IACpD;;OAEG;IACH,6EAAsD,CAAA;AACxD,CAAC,EApBW,mBAAmB,KAAnB,mBAAmB,QAoB9B;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC,gBAAgB,CAAC;AAEzE;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAa,CAAC,GAAG,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n/**\n * Current version of the `@azure/identity` package.\n */\nexport const SDK_VERSION = `4.14.0-beta.2`;\n\n/**\n * The default client ID for authentication\n * @internal\n */\n// TODO: temporary - this is the Azure CLI clientID - we'll replace it when\n// Developer Sign On application is available\n// https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/src/Constants.cs#L9\nexport const DeveloperSignOnClientId = \"04b07795-8ddb-461a-bbee-02f9e1bf7b46\";\n\n/**\n * The default tenant for authentication\n * @internal\n */\nexport const DefaultTenantId = \"common\";\n\n/**\n * A list of known Azure authority hosts\n */\nexport enum AzureAuthorityHosts {\n /**\n * China-based Azure Authority Host\n */\n AzureChina = \"https://login.chinacloudapi.cn\",\n /**\n * Germany-based Azure Authority Host\n *\n * @deprecated Microsoft Cloud Germany was closed on October 29th, 2021.\n *\n * */\n AzureGermany = \"https://login.microsoftonline.de\",\n /**\n * US Government Azure Authority Host\n */\n AzureGovernment = \"https://login.microsoftonline.us\",\n /**\n * Public Cloud Azure Authority Host\n */\n AzurePublicCloud = \"https://login.microsoftonline.com\",\n}\n\n/**\n * @internal\n * The default authority host.\n */\nexport const DefaultAuthorityHost = AzureAuthorityHosts.AzurePublicCloud;\n\n/**\n * @internal\n * The default environment host for Azure Public Cloud\n */\nexport const DefaultAuthority = \"login.microsoftonline.com\";\n\n/**\n * @internal\n * Allow acquiring tokens for any tenant for multi-tentant auth.\n */\nexport const ALL_TENANTS: string[] = [\"*\"];\n\n/**\n * @internal\n */\nexport const CACHE_CAE_SUFFIX = \"cae\";\n\n/**\n * @internal\n */\nexport const CACHE_NON_CAE_SUFFIX = \"nocae\";\n\n/**\n * @internal\n *\n * The default name for the cache persistence plugin.\n * Matches the constant defined in the cache persistence package.\n */\nexport const DEFAULT_TOKEN_CACHE_NAME = \"msal.cache\";\n"]}
|
|
@@ -6,7 +6,7 @@ export declare const logger: import("../util/logging.js").CredentialLogger;
|
|
|
6
6
|
/**
|
|
7
7
|
* Enables multiple `TokenCredential` implementations to be tried in order until
|
|
8
8
|
* one of the getToken methods returns an access token. For more information, see
|
|
9
|
-
* [ChainedTokenCredential overview](https://aka.ms/azsdk/js/identity/credential-chains#
|
|
9
|
+
* [ChainedTokenCredential overview](https://aka.ms/azsdk/js/identity/credential-chains#chainedtokencredential-overview).
|
|
10
10
|
*/
|
|
11
11
|
export declare class ChainedTokenCredential implements TokenCredential {
|
|
12
12
|
private _sources;
|
|
@@ -10,7 +10,7 @@ export const logger = credentialLogger("ChainedTokenCredential");
|
|
|
10
10
|
/**
|
|
11
11
|
* Enables multiple `TokenCredential` implementations to be tried in order until
|
|
12
12
|
* one of the getToken methods returns an access token. For more information, see
|
|
13
|
-
* [ChainedTokenCredential overview](https://aka.ms/azsdk/js/identity/credential-chains#
|
|
13
|
+
* [ChainedTokenCredential overview](https://aka.ms/azsdk/js/identity/credential-chains#chainedtokencredential-overview).
|
|
14
14
|
*/
|
|
15
15
|
export class ChainedTokenCredential {
|
|
16
16
|
_sources = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chainedTokenCredential.js","sourceRoot":"","sources":["../../../src/credentials/chainedTokenCredential.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAGlC,OAAO,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,gBAAgB,CAAC,wBAAwB,CAAC,CAAC;AAEjE;;;;GAIG;AACH,MAAM,OAAO,sBAAsB;IACzB,QAAQ,GAAsB,EAAE,CAAC;IAEzC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,YAAY,GAAG,OAA0B;QACvC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,CAAC,MAAyB,EAAE,UAA2B,EAAE;QACrE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC5B,MAAyB,EACzB,UAA2B,EAAE;QAE7B,IAAI,KAAK,GAAuB,IAAI,CAAC;QACrC,IAAI,oBAAqC,CAAC;QAC1C,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,OAAO,aAAa,CAAC,QAAQ,CAC3B,iCAAiC,EACjC,OAAO,EACP,KAAK,EAAE,cAAc,EAAE,EAAE;YACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;gBAChE,IAAI,CAAC;oBACH,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;oBAChE,oBAAoB,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAC1C,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,IACE,GAAG,CAAC,IAAI,KAAK,4BAA4B;wBACzC,GAAG,CAAC,IAAI,KAAK,6BAA6B,EAC1C,CAAC;wBACD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBACnB,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;wBAC/C,MAAM,GAAG,CAAC;oBACZ,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,IAAI,4BAA4B,CAC1C,MAAM,EACN,+CAA+C,CAChD,CAAC;gBACF,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC/C,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,MAAM,CAAC,QAAQ,CAAC,IAAI,CAClB,cAAc,oBAAoB,CAAC,WAAW,CAAC,IAAI,KAAK,aAAa,CAAC,MAAM,CAAC,EAAE,CAChF,CAAC;YAEF,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,MAAM,IAAI,0BAA0B,CAAC,kCAAkC,CAAC,CAAC;YAC3E,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;QACzC,CAAC,CACF,CAAC;IACJ,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport { AggregateAuthenticationError, CredentialUnavailableError } from \"../errors.js\";\nimport { credentialLogger, formatError, formatSuccess } from \"../util/logging.js\";\nimport { tracingClient } from \"../util/tracing.js\";\n\n/**\n * @internal\n */\nexport const logger = credentialLogger(\"ChainedTokenCredential\");\n\n/**\n * Enables multiple `TokenCredential` implementations to be tried in order until\n * one of the getToken methods returns an access token. For more information, see\n * [ChainedTokenCredential overview](https://aka.ms/azsdk/js/identity/credential-chains#
|
|
1
|
+
{"version":3,"file":"chainedTokenCredential.js","sourceRoot":"","sources":["../../../src/credentials/chainedTokenCredential.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAGlC,OAAO,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,gBAAgB,CAAC,wBAAwB,CAAC,CAAC;AAEjE;;;;GAIG;AACH,MAAM,OAAO,sBAAsB;IACzB,QAAQ,GAAsB,EAAE,CAAC;IAEzC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,YAAY,GAAG,OAA0B;QACvC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,CAAC,MAAyB,EAAE,UAA2B,EAAE;QACrE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC5B,MAAyB,EACzB,UAA2B,EAAE;QAE7B,IAAI,KAAK,GAAuB,IAAI,CAAC;QACrC,IAAI,oBAAqC,CAAC;QAC1C,MAAM,MAAM,GAAY,EAAE,CAAC;QAE3B,OAAO,aAAa,CAAC,QAAQ,CAC3B,iCAAiC,EACjC,OAAO,EACP,KAAK,EAAE,cAAc,EAAE,EAAE;YACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;gBAChE,IAAI,CAAC;oBACH,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;oBAChE,oBAAoB,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAC1C,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,IACE,GAAG,CAAC,IAAI,KAAK,4BAA4B;wBACzC,GAAG,CAAC,IAAI,KAAK,6BAA6B,EAC1C,CAAC;wBACD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBACnB,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;wBAC/C,MAAM,GAAG,CAAC;oBACZ,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,IAAI,4BAA4B,CAC1C,MAAM,EACN,+CAA+C,CAChD,CAAC;gBACF,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC/C,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,MAAM,CAAC,QAAQ,CAAC,IAAI,CAClB,cAAc,oBAAoB,CAAC,WAAW,CAAC,IAAI,KAAK,aAAa,CAAC,MAAM,CAAC,EAAE,CAChF,CAAC;YAEF,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,MAAM,IAAI,0BAA0B,CAAC,kCAAkC,CAAC,CAAC;YAC3E,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;QACzC,CAAC,CACF,CAAC;IACJ,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport { AggregateAuthenticationError, CredentialUnavailableError } from \"../errors.js\";\nimport { credentialLogger, formatError, formatSuccess } from \"../util/logging.js\";\nimport { tracingClient } from \"../util/tracing.js\";\n\n/**\n * @internal\n */\nexport const logger = credentialLogger(\"ChainedTokenCredential\");\n\n/**\n * Enables multiple `TokenCredential` implementations to be tried in order until\n * one of the getToken methods returns an access token. For more information, see\n * [ChainedTokenCredential overview](https://aka.ms/azsdk/js/identity/credential-chains#chainedtokencredential-overview).\n */\nexport class ChainedTokenCredential implements TokenCredential {\n private _sources: TokenCredential[] = [];\n\n /**\n * Creates an instance of ChainedTokenCredential using the given credentials.\n *\n * @param sources - `TokenCredential` implementations to be tried in order.\n *\n * Example usage:\n * ```ts snippet:chained_token_credential_example\n * import { ClientSecretCredential, ChainedTokenCredential } from \"@azure/identity\";\n *\n * const tenantId = \"<tenant-id>\";\n * const clientId = \"<client-id>\";\n * const clientSecret = \"<client-secret>\";\n * const anotherClientId = \"<another-client-id>\";\n * const anotherSecret = \"<another-client-secret>\";\n *\n * const firstCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);\n * const secondCredential = new ClientSecretCredential(tenantId, anotherClientId, anotherSecret);\n *\n * const credentialChain = new ChainedTokenCredential(firstCredential, secondCredential);\n * ```\n */\n constructor(...sources: TokenCredential[]) {\n this._sources = sources;\n }\n\n /**\n * Returns the first access token returned by one of the chained\n * `TokenCredential` implementations. Throws an {@link AggregateAuthenticationError}\n * when one or more credentials throws an {@link AuthenticationError} and\n * no credentials have returned an access token.\n *\n * This method is called automatically by Azure SDK client libraries. You may call this method\n * directly, but you must also handle token caching and token refreshing.\n *\n * @param scopes - The list of scopes for which the token will have access.\n * @param options - The options used to configure any requests this\n * `TokenCredential` implementation might make.\n */\n async getToken(scopes: string | string[], options: GetTokenOptions = {}): Promise<AccessToken> {\n const { token } = await this.getTokenInternal(scopes, options);\n return token;\n }\n\n private async getTokenInternal(\n scopes: string | string[],\n options: GetTokenOptions = {},\n ): Promise<{ token: AccessToken; successfulCredential: TokenCredential }> {\n let token: AccessToken | null = null;\n let successfulCredential: TokenCredential;\n const errors: Error[] = [];\n\n return tracingClient.withSpan(\n \"ChainedTokenCredential.getToken\",\n options,\n async (updatedOptions) => {\n for (let i = 0; i < this._sources.length && token === null; i++) {\n try {\n token = await this._sources[i].getToken(scopes, updatedOptions);\n successfulCredential = this._sources[i];\n } catch (err: any) {\n if (\n err.name === \"CredentialUnavailableError\" ||\n err.name === \"AuthenticationRequiredError\"\n ) {\n errors.push(err);\n } else {\n logger.getToken.info(formatError(scopes, err));\n throw err;\n }\n }\n }\n\n if (!token && errors.length > 0) {\n const err = new AggregateAuthenticationError(\n errors,\n \"ChainedTokenCredential authentication failed.\",\n );\n logger.getToken.info(formatError(scopes, err));\n throw err;\n }\n\n logger.getToken.info(\n `Result for ${successfulCredential.constructor.name}: ${formatSuccess(scopes)}`,\n );\n\n if (token === null) {\n throw new CredentialUnavailableError(\"Failed to retrieve a valid token\");\n }\n return { token, successfulCredential };\n },\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clientCertificateCredential.d.ts","sourceRoot":"","sources":["../../../src/credentials/clientCertificateCredential.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAStF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,yCAAyC,CAAC;AAIlG,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAC/B,mCAAmC,EACpC,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"clientCertificateCredential.d.ts","sourceRoot":"","sources":["../../../src/credentials/clientCertificateCredential.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAStF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,yCAAyC,CAAC;AAIlG,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAC/B,mCAAmC,EACpC,MAAM,wCAAwC,CAAC;AAMhD;;;;;;;GAOG;AACH,qBAAa,2BAA4B,YAAW,eAAe;IACjE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,4BAA4B,CAAW;IAC/C,OAAO,CAAC,wBAAwB,CAA8C;IAC9E,OAAO,CAAC,oBAAoB,CAAC,CAAU;IACvC,OAAO,CAAC,UAAU,CAAa;IAE/B;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,kCAAkC;IAE9C;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,mCAAmC,EAClD,OAAO,CAAC,EAAE,kCAAkC;IAE9C;;;;;;;;;OASG;gBAED,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,+BAA+B,EAC9C,OAAO,CAAC,EAAE,kCAAkC;IA+C9C;;;;;;;OAOG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;YAehF,sBAAsB;CA6BrC;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,wBAAwB,EAAE,2CAA2C,EACrE,oBAAoB,EAAE,OAAO,GAC5B,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAC,GAAG;IAAE,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC,CAyBjF"}
|
|
@@ -6,6 +6,7 @@ import { processMultiTenantRequest, resolveAdditionallyAllowedTenantIds, } from
|
|
|
6
6
|
import { credentialLogger } from "../util/logging.js";
|
|
7
7
|
import { readFile } from "node:fs/promises";
|
|
8
8
|
import { tracingClient } from "../util/tracing.js";
|
|
9
|
+
import { extractPemCertificateKeys } from "../util/certificatesUtils.js";
|
|
9
10
|
const credentialName = "ClientCertificateCredential";
|
|
10
11
|
const logger = credentialLogger(credentialName);
|
|
11
12
|
/**
|
|
@@ -107,19 +108,7 @@ export async function parseCertificate(certificateConfiguration, sendCertificate
|
|
|
107
108
|
.certificatePath;
|
|
108
109
|
const certificateContents = certificate || (await readFile(certificatePath, "utf8"));
|
|
109
110
|
const x5c = sendCertificateChain ? certificateContents : undefined;
|
|
110
|
-
const
|
|
111
|
-
const publicKeys = [];
|
|
112
|
-
// Match all possible certificates, in the order they are in the file. These will form the chain that is used for x5c
|
|
113
|
-
let match;
|
|
114
|
-
do {
|
|
115
|
-
match = certificatePattern.exec(certificateContents);
|
|
116
|
-
if (match) {
|
|
117
|
-
publicKeys.push(match[3]);
|
|
118
|
-
}
|
|
119
|
-
} while (match);
|
|
120
|
-
if (publicKeys.length === 0) {
|
|
121
|
-
throw new Error("The file at the specified path does not contain a PEM-encoded certificate.");
|
|
122
|
-
}
|
|
111
|
+
const publicKeys = extractPemCertificateKeys(certificateContents);
|
|
123
112
|
const thumbprint = createHash("sha1") // CodeQL [SM04514] Needed for backward compatibility reason
|
|
124
113
|
.update(Buffer.from(publicKeys[0], "base64"))
|
|
125
114
|
.digest("hex")
|