@microsoft/vscode-azext-azureauth 4.0.3 → 4.1.1
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/AzureFederatedCredentialsGuide.md +174 -174
- package/CHANGELOG.md +98 -90
- package/LICENSE.md +21 -21
- package/README.md +156 -152
- package/out/src/AzureAuthentication.d.ts +21 -21
- package/out/src/AzureAuthentication.js +6 -6
- package/out/src/AzureDevOpsSubscriptionProvider.d.ts +68 -68
- package/out/src/AzureDevOpsSubscriptionProvider.js +256 -256
- package/out/src/AzureSubscription.d.ts +49 -49
- package/out/src/AzureSubscription.js +6 -6
- package/out/src/AzureSubscriptionProvider.d.ts +82 -63
- package/out/src/AzureSubscriptionProvider.js +6 -6
- package/out/src/AzureTenant.d.ts +5 -5
- package/out/src/AzureTenant.js +6 -6
- package/out/src/NotSignedInError.d.ts +15 -15
- package/out/src/NotSignedInError.js +29 -29
- package/out/src/VSCodeAzureSubscriptionProvider.d.ts +117 -113
- package/out/src/VSCodeAzureSubscriptionProvider.js +394 -386
- package/out/src/getSessionFromVSCode.d.ts +12 -12
- package/out/src/getSessionFromVSCode.js +64 -64
- package/out/src/index.d.ts +10 -10
- package/out/src/index.js +30 -30
- package/out/src/signInToTenant.d.ts +6 -6
- package/out/src/signInToTenant.js +64 -64
- package/out/src/utils/configuredAzureEnv.d.ts +24 -24
- package/out/src/utils/configuredAzureEnv.js +94 -94
- package/out/src/utils/getUnauthenticatedTenants.d.ts +6 -6
- package/out/src/utils/getUnauthenticatedTenants.js +57 -57
- package/package.json +61 -61
|
@@ -1,257 +1,257 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*---------------------------------------------------------------------------------------------
|
|
3
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
-
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
-
*--------------------------------------------------------------------------------------------*/
|
|
6
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
16
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
17
|
-
var m = o[Symbol.asyncIterator], i;
|
|
18
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
19
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
20
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
21
|
-
};
|
|
22
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.AzureDevOpsSubscriptionProvider = exports.createAzureDevOpsSubscriptionProviderFactory = void 0;
|
|
24
|
-
const vscode_1 = require("vscode");
|
|
25
|
-
const configuredAzureEnv_1 = require("./utils/configuredAzureEnv");
|
|
26
|
-
let azureDevOpsSubscriptionProvider;
|
|
27
|
-
function createAzureDevOpsSubscriptionProviderFactory(initializer) {
|
|
28
|
-
return () => __awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
azureDevOpsSubscriptionProvider !== null && azureDevOpsSubscriptionProvider !== void 0 ? azureDevOpsSubscriptionProvider : (azureDevOpsSubscriptionProvider = new AzureDevOpsSubscriptionProvider(initializer));
|
|
30
|
-
return azureDevOpsSubscriptionProvider;
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
exports.createAzureDevOpsSubscriptionProviderFactory = createAzureDevOpsSubscriptionProviderFactory;
|
|
34
|
-
/**
|
|
35
|
-
* AzureSubscriptionProvider implemented to authenticate via federated DevOps service connection, using workflow identity federation
|
|
36
|
-
* To learn how to configure your DevOps environment to use this provider, refer to the README.md
|
|
37
|
-
* NOTE: This provider is only available when running in an Azure DevOps pipeline
|
|
38
|
-
* Reference: https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation
|
|
39
|
-
*/
|
|
40
|
-
class AzureDevOpsSubscriptionProvider {
|
|
41
|
-
constructor({ serviceConnectionId, domain, clientId }) {
|
|
42
|
-
this.onDidSignIn = () => { return new vscode_1.Disposable(() => { }); };
|
|
43
|
-
this.onDidSignOut = () => { return new vscode_1.Disposable(() => { }); };
|
|
44
|
-
if (!serviceConnectionId || !domain || !clientId) {
|
|
45
|
-
throw new Error(`Missing initializer values to identify Azure DevOps federated service connection\n
|
|
46
|
-
Values provided:\n
|
|
47
|
-
serviceConnectionId: ${serviceConnectionId ? "✅" : "❌"}\n
|
|
48
|
-
domain: ${domain ? "✅" : "❌"}\n
|
|
49
|
-
clientId: ${clientId ? "✅" : "❌"}\n
|
|
50
|
-
`);
|
|
51
|
-
}
|
|
52
|
-
this._SERVICE_CONNECTION_ID = serviceConnectionId;
|
|
53
|
-
this._DOMAIN = domain;
|
|
54
|
-
this._CLIENT_ID = clientId;
|
|
55
|
-
}
|
|
56
|
-
getSubscriptions(_filter) {
|
|
57
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
// ignore the filter setting because not every consumer of this provider will use the Resources extension
|
|
59
|
-
const results = [];
|
|
60
|
-
for (const tenant of yield this.getTenants()) {
|
|
61
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
62
|
-
const tenantId = tenant.tenantId;
|
|
63
|
-
results.push(...yield this.getSubscriptionsForTenant(tenantId));
|
|
64
|
-
}
|
|
65
|
-
const sortSubscriptions = (subscriptions) => subscriptions.sort((a, b) => a.name.localeCompare(b.name));
|
|
66
|
-
return sortSubscriptions(results);
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
isSignedIn() {
|
|
70
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
-
return !!this._tokenCredential;
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
signIn() {
|
|
75
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
-
this._tokenCredential = yield getTokenCredential(this._SERVICE_CONNECTION_ID, this._DOMAIN, this._CLIENT_ID);
|
|
77
|
-
return !!this._tokenCredential;
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
signOut() {
|
|
81
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
-
this._tokenCredential = undefined;
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
getTenants() {
|
|
86
|
-
var _a;
|
|
87
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
-
return [{
|
|
89
|
-
tenantId: (_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.tenantId,
|
|
90
|
-
account: {
|
|
91
|
-
id: "test-account-id",
|
|
92
|
-
label: "test-account",
|
|
93
|
-
}
|
|
94
|
-
}];
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Gets the subscriptions for a given tenant.
|
|
99
|
-
*
|
|
100
|
-
* @param tenantId The tenant ID to get subscriptions for.
|
|
101
|
-
*
|
|
102
|
-
* @returns The list of subscriptions for the tenant.
|
|
103
|
-
*/
|
|
104
|
-
getSubscriptionsForTenant(tenantId) {
|
|
105
|
-
var _a, e_1, _b, _c;
|
|
106
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
-
const { client, credential, authentication } = yield this.getSubscriptionClient(tenantId);
|
|
108
|
-
const environment = (0, configuredAzureEnv_1.getConfiguredAzureEnv)();
|
|
109
|
-
const subscriptions = [];
|
|
110
|
-
try {
|
|
111
|
-
for (var _d = true, _e = __asyncValues(client.subscriptions.list()), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
|
112
|
-
_c = _f.value;
|
|
113
|
-
_d = false;
|
|
114
|
-
try {
|
|
115
|
-
const subscription = _c;
|
|
116
|
-
subscriptions.push({
|
|
117
|
-
authentication,
|
|
118
|
-
environment: environment,
|
|
119
|
-
credential: credential,
|
|
120
|
-
isCustomCloud: environment.isCustomCloud,
|
|
121
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
122
|
-
name: subscription.displayName,
|
|
123
|
-
subscriptionId: subscription.subscriptionId,
|
|
124
|
-
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
125
|
-
tenantId,
|
|
126
|
-
account: {
|
|
127
|
-
id: "test-account-id",
|
|
128
|
-
label: "test-account",
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
finally {
|
|
133
|
-
_d = true;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
138
|
-
finally {
|
|
139
|
-
try {
|
|
140
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
141
|
-
}
|
|
142
|
-
finally { if (e_1) throw e_1.error; }
|
|
143
|
-
}
|
|
144
|
-
return subscriptions;
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Gets a fully-configured subscription client for a given tenant ID
|
|
149
|
-
*
|
|
150
|
-
* @param tenantId (Optional) The tenant ID to get a client for
|
|
151
|
-
*
|
|
152
|
-
* @returns A client, the credential used by the client, and the authentication function
|
|
153
|
-
*/
|
|
154
|
-
getSubscriptionClient(_tenantId, scopes) {
|
|
155
|
-
var _a, _b;
|
|
156
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
157
|
-
const armSubs = yield Promise.resolve().then(() => require('@azure/arm-resources-subscriptions'));
|
|
158
|
-
if (!this._tokenCredential) {
|
|
159
|
-
throw new Error('Not signed in');
|
|
160
|
-
}
|
|
161
|
-
const accessToken = ((_b = (yield ((_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.getToken("https://management.azure.com/.default")))) === null || _b === void 0 ? void 0 : _b.token) || '';
|
|
162
|
-
const getSession = () => {
|
|
163
|
-
var _a, _b, _c, _d;
|
|
164
|
-
return {
|
|
165
|
-
accessToken,
|
|
166
|
-
id: ((_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.tenantId) || '',
|
|
167
|
-
account: {
|
|
168
|
-
id: ((_b = this._tokenCredential) === null || _b === void 0 ? void 0 : _b.tenantId) || '',
|
|
169
|
-
label: ((_c = this._tokenCredential) === null || _c === void 0 ? void 0 : _c.tenantId) || '',
|
|
170
|
-
},
|
|
171
|
-
tenantId: ((_d = this._tokenCredential) === null || _d === void 0 ? void 0 : _d.tenantId) || '',
|
|
172
|
-
scopes: scopes || [],
|
|
173
|
-
};
|
|
174
|
-
};
|
|
175
|
-
return {
|
|
176
|
-
client: new armSubs.SubscriptionClient(this._tokenCredential),
|
|
177
|
-
credential: this._tokenCredential,
|
|
178
|
-
authentication: {
|
|
179
|
-
getSession,
|
|
180
|
-
getSessionWithScopes: getSession,
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
exports.AzureDevOpsSubscriptionProvider = AzureDevOpsSubscriptionProvider;
|
|
187
|
-
/*
|
|
188
|
-
* @param serviceConnectionId The resource ID of the Azure DevOps federated service connection,
|
|
189
|
-
* which can be found on the `resourceId` field of the URL at the address bar when viewing the service connection in the Azure DevOps portal
|
|
190
|
-
* @param domain The `Tenant ID` field of the service connection properties
|
|
191
|
-
* @param clientId The `Service Principal Id` field of the service connection properties
|
|
192
|
-
*/
|
|
193
|
-
function getTokenCredential(serviceConnectionId, domain, clientId) {
|
|
194
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
195
|
-
if (!process.env.AGENT_BUILDDIRECTORY) {
|
|
196
|
-
// Assume that AGENT_BUILDDIRECTORY is set if running in an Azure DevOps pipeline.
|
|
197
|
-
// So when not running in an Azure DevOps pipeline, throw an error since we cannot use the DevOps federated service connection credential.
|
|
198
|
-
throw new Error(`Cannot create DevOps federated service connection credential outside of an Azure DevOps pipeline.`);
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
console.log(`Creating DevOps federated service connection credential for service connection..`);
|
|
202
|
-
// Pre-defined DevOps variable reference: https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops
|
|
203
|
-
const systemAccessToken = process.env.SYSTEM_ACCESSTOKEN;
|
|
204
|
-
const teamFoundationCollectionUri = process.env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI;
|
|
205
|
-
const teamProjectId = process.env.SYSTEM_TEAMPROJECTID;
|
|
206
|
-
const planId = process.env.SYSTEM_PLANID;
|
|
207
|
-
const jobId = process.env.SYSTEM_JOBID;
|
|
208
|
-
if (!systemAccessToken || !teamFoundationCollectionUri || !teamProjectId || !planId || !jobId) {
|
|
209
|
-
throw new Error(`Azure DevOps environment variables are not set.\n
|
|
210
|
-
process.env.SYSTEM_ACCESSTOKEN: ${process.env.SYSTEM_ACCESSTOKEN ? "✅" : "❌"}\n
|
|
211
|
-
process.env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI: ${process.env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI ? "✅" : "❌"}\n
|
|
212
|
-
process.env.SYSTEM_TEAMPROJECTID: ${process.env.SYSTEM_TEAMPROJECTID ? "✅" : "❌"}\n
|
|
213
|
-
process.env.SYSTEM_PLANID: ${process.env.SYSTEM_PLANID ? "✅" : "❌"}\n
|
|
214
|
-
process.env.SYSTEM_JOBID: ${process.env.SYSTEM_JOBID ? "✅" : "❌"}\n
|
|
215
|
-
REMEMBER: process.env.SYSTEM_ACCESSTOKEN must be explicitly mapped!\n
|
|
216
|
-
https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken
|
|
217
|
-
`);
|
|
218
|
-
}
|
|
219
|
-
const oidcRequestUrl = `${teamFoundationCollectionUri}${teamProjectId}/_apis/distributedtask/hubs/build/plans/${planId}/jobs/${jobId}/oidctoken?api-version=7.1-preview.1&serviceConnectionId=${serviceConnectionId}`;
|
|
220
|
-
const { ClientAssertionCredential } = yield Promise.resolve().then(() => require("@azure/identity"));
|
|
221
|
-
return new ClientAssertionCredential(domain, clientId, () => __awaiter(this, void 0, void 0, function* () { return yield requestOidcToken(oidcRequestUrl, systemAccessToken); }));
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* API reference: https://learn.microsoft.com/en-us/rest/api/azure/devops/distributedtask/oidctoken/create
|
|
227
|
-
*/
|
|
228
|
-
function requestOidcToken(oidcRequestUrl, systemAccessToken) {
|
|
229
|
-
var _a;
|
|
230
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
231
|
-
const { ServiceClient } = yield Promise.resolve().then(() => require('@azure/core-client'));
|
|
232
|
-
const { createHttpHeaders, createPipelineRequest } = yield Promise.resolve().then(() => require('@azure/core-rest-pipeline'));
|
|
233
|
-
const genericClient = new ServiceClient();
|
|
234
|
-
const request = createPipelineRequest({
|
|
235
|
-
url: oidcRequestUrl,
|
|
236
|
-
method: "POST",
|
|
237
|
-
headers: createHttpHeaders({
|
|
238
|
-
"Content-Type": "application/json",
|
|
239
|
-
"Authorization": `Bearer ${systemAccessToken}`
|
|
240
|
-
})
|
|
241
|
-
});
|
|
242
|
-
const response = yield genericClient.sendRequest(request);
|
|
243
|
-
const body = ((_a = response.bodyAsText) === null || _a === void 0 ? void 0 : _a.toString()) || "";
|
|
244
|
-
if (response.status !== 200) {
|
|
245
|
-
throw new Error(`Failed to get OIDC token:\n
|
|
246
|
-
Response status: ${response.status}\n
|
|
247
|
-
Response body: ${body}\n
|
|
248
|
-
Response headers: ${JSON.stringify(response.headers.toJSON())}
|
|
249
|
-
`);
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
console.log(`Successfully got OIDC token with status ${response.status}`);
|
|
253
|
-
}
|
|
254
|
-
return JSON.parse(body).oidcToken;
|
|
255
|
-
});
|
|
256
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
16
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
17
|
+
var m = o[Symbol.asyncIterator], i;
|
|
18
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
19
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
20
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.AzureDevOpsSubscriptionProvider = exports.createAzureDevOpsSubscriptionProviderFactory = void 0;
|
|
24
|
+
const vscode_1 = require("vscode");
|
|
25
|
+
const configuredAzureEnv_1 = require("./utils/configuredAzureEnv");
|
|
26
|
+
let azureDevOpsSubscriptionProvider;
|
|
27
|
+
function createAzureDevOpsSubscriptionProviderFactory(initializer) {
|
|
28
|
+
return () => __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
azureDevOpsSubscriptionProvider !== null && azureDevOpsSubscriptionProvider !== void 0 ? azureDevOpsSubscriptionProvider : (azureDevOpsSubscriptionProvider = new AzureDevOpsSubscriptionProvider(initializer));
|
|
30
|
+
return azureDevOpsSubscriptionProvider;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
exports.createAzureDevOpsSubscriptionProviderFactory = createAzureDevOpsSubscriptionProviderFactory;
|
|
34
|
+
/**
|
|
35
|
+
* AzureSubscriptionProvider implemented to authenticate via federated DevOps service connection, using workflow identity federation
|
|
36
|
+
* To learn how to configure your DevOps environment to use this provider, refer to the README.md
|
|
37
|
+
* NOTE: This provider is only available when running in an Azure DevOps pipeline
|
|
38
|
+
* Reference: https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation
|
|
39
|
+
*/
|
|
40
|
+
class AzureDevOpsSubscriptionProvider {
|
|
41
|
+
constructor({ serviceConnectionId, domain, clientId }) {
|
|
42
|
+
this.onDidSignIn = () => { return new vscode_1.Disposable(() => { }); };
|
|
43
|
+
this.onDidSignOut = () => { return new vscode_1.Disposable(() => { }); };
|
|
44
|
+
if (!serviceConnectionId || !domain || !clientId) {
|
|
45
|
+
throw new Error(`Missing initializer values to identify Azure DevOps federated service connection\n
|
|
46
|
+
Values provided:\n
|
|
47
|
+
serviceConnectionId: ${serviceConnectionId ? "✅" : "❌"}\n
|
|
48
|
+
domain: ${domain ? "✅" : "❌"}\n
|
|
49
|
+
clientId: ${clientId ? "✅" : "❌"}\n
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
this._SERVICE_CONNECTION_ID = serviceConnectionId;
|
|
53
|
+
this._DOMAIN = domain;
|
|
54
|
+
this._CLIENT_ID = clientId;
|
|
55
|
+
}
|
|
56
|
+
getSubscriptions(_filter) {
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
// ignore the filter setting because not every consumer of this provider will use the Resources extension
|
|
59
|
+
const results = [];
|
|
60
|
+
for (const tenant of yield this.getTenants()) {
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
62
|
+
const tenantId = tenant.tenantId;
|
|
63
|
+
results.push(...yield this.getSubscriptionsForTenant(tenantId));
|
|
64
|
+
}
|
|
65
|
+
const sortSubscriptions = (subscriptions) => subscriptions.sort((a, b) => a.name.localeCompare(b.name));
|
|
66
|
+
return sortSubscriptions(results);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
isSignedIn() {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
return !!this._tokenCredential;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
signIn() {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
this._tokenCredential = yield getTokenCredential(this._SERVICE_CONNECTION_ID, this._DOMAIN, this._CLIENT_ID);
|
|
77
|
+
return !!this._tokenCredential;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
signOut() {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
this._tokenCredential = undefined;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
getTenants() {
|
|
86
|
+
var _a;
|
|
87
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
return [{
|
|
89
|
+
tenantId: (_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.tenantId,
|
|
90
|
+
account: {
|
|
91
|
+
id: "test-account-id",
|
|
92
|
+
label: "test-account",
|
|
93
|
+
}
|
|
94
|
+
}];
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Gets the subscriptions for a given tenant.
|
|
99
|
+
*
|
|
100
|
+
* @param tenantId The tenant ID to get subscriptions for.
|
|
101
|
+
*
|
|
102
|
+
* @returns The list of subscriptions for the tenant.
|
|
103
|
+
*/
|
|
104
|
+
getSubscriptionsForTenant(tenantId) {
|
|
105
|
+
var _a, e_1, _b, _c;
|
|
106
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
+
const { client, credential, authentication } = yield this.getSubscriptionClient(tenantId);
|
|
108
|
+
const environment = (0, configuredAzureEnv_1.getConfiguredAzureEnv)();
|
|
109
|
+
const subscriptions = [];
|
|
110
|
+
try {
|
|
111
|
+
for (var _d = true, _e = __asyncValues(client.subscriptions.list()), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
|
112
|
+
_c = _f.value;
|
|
113
|
+
_d = false;
|
|
114
|
+
try {
|
|
115
|
+
const subscription = _c;
|
|
116
|
+
subscriptions.push({
|
|
117
|
+
authentication,
|
|
118
|
+
environment: environment,
|
|
119
|
+
credential: credential,
|
|
120
|
+
isCustomCloud: environment.isCustomCloud,
|
|
121
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
122
|
+
name: subscription.displayName,
|
|
123
|
+
subscriptionId: subscription.subscriptionId,
|
|
124
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
125
|
+
tenantId,
|
|
126
|
+
account: {
|
|
127
|
+
id: "test-account-id",
|
|
128
|
+
label: "test-account",
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
_d = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
138
|
+
finally {
|
|
139
|
+
try {
|
|
140
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
141
|
+
}
|
|
142
|
+
finally { if (e_1) throw e_1.error; }
|
|
143
|
+
}
|
|
144
|
+
return subscriptions;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Gets a fully-configured subscription client for a given tenant ID
|
|
149
|
+
*
|
|
150
|
+
* @param tenantId (Optional) The tenant ID to get a client for
|
|
151
|
+
*
|
|
152
|
+
* @returns A client, the credential used by the client, and the authentication function
|
|
153
|
+
*/
|
|
154
|
+
getSubscriptionClient(_tenantId, scopes) {
|
|
155
|
+
var _a, _b;
|
|
156
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
157
|
+
const armSubs = yield Promise.resolve().then(() => require('@azure/arm-resources-subscriptions'));
|
|
158
|
+
if (!this._tokenCredential) {
|
|
159
|
+
throw new Error('Not signed in');
|
|
160
|
+
}
|
|
161
|
+
const accessToken = ((_b = (yield ((_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.getToken("https://management.azure.com/.default")))) === null || _b === void 0 ? void 0 : _b.token) || '';
|
|
162
|
+
const getSession = () => {
|
|
163
|
+
var _a, _b, _c, _d;
|
|
164
|
+
return {
|
|
165
|
+
accessToken,
|
|
166
|
+
id: ((_a = this._tokenCredential) === null || _a === void 0 ? void 0 : _a.tenantId) || '',
|
|
167
|
+
account: {
|
|
168
|
+
id: ((_b = this._tokenCredential) === null || _b === void 0 ? void 0 : _b.tenantId) || '',
|
|
169
|
+
label: ((_c = this._tokenCredential) === null || _c === void 0 ? void 0 : _c.tenantId) || '',
|
|
170
|
+
},
|
|
171
|
+
tenantId: ((_d = this._tokenCredential) === null || _d === void 0 ? void 0 : _d.tenantId) || '',
|
|
172
|
+
scopes: scopes || [],
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
return {
|
|
176
|
+
client: new armSubs.SubscriptionClient(this._tokenCredential),
|
|
177
|
+
credential: this._tokenCredential,
|
|
178
|
+
authentication: {
|
|
179
|
+
getSession,
|
|
180
|
+
getSessionWithScopes: getSession,
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.AzureDevOpsSubscriptionProvider = AzureDevOpsSubscriptionProvider;
|
|
187
|
+
/*
|
|
188
|
+
* @param serviceConnectionId The resource ID of the Azure DevOps federated service connection,
|
|
189
|
+
* which can be found on the `resourceId` field of the URL at the address bar when viewing the service connection in the Azure DevOps portal
|
|
190
|
+
* @param domain The `Tenant ID` field of the service connection properties
|
|
191
|
+
* @param clientId The `Service Principal Id` field of the service connection properties
|
|
192
|
+
*/
|
|
193
|
+
function getTokenCredential(serviceConnectionId, domain, clientId) {
|
|
194
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
195
|
+
if (!process.env.AGENT_BUILDDIRECTORY) {
|
|
196
|
+
// Assume that AGENT_BUILDDIRECTORY is set if running in an Azure DevOps pipeline.
|
|
197
|
+
// So when not running in an Azure DevOps pipeline, throw an error since we cannot use the DevOps federated service connection credential.
|
|
198
|
+
throw new Error(`Cannot create DevOps federated service connection credential outside of an Azure DevOps pipeline.`);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
console.log(`Creating DevOps federated service connection credential for service connection..`);
|
|
202
|
+
// Pre-defined DevOps variable reference: https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops
|
|
203
|
+
const systemAccessToken = process.env.SYSTEM_ACCESSTOKEN;
|
|
204
|
+
const teamFoundationCollectionUri = process.env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI;
|
|
205
|
+
const teamProjectId = process.env.SYSTEM_TEAMPROJECTID;
|
|
206
|
+
const planId = process.env.SYSTEM_PLANID;
|
|
207
|
+
const jobId = process.env.SYSTEM_JOBID;
|
|
208
|
+
if (!systemAccessToken || !teamFoundationCollectionUri || !teamProjectId || !planId || !jobId) {
|
|
209
|
+
throw new Error(`Azure DevOps environment variables are not set.\n
|
|
210
|
+
process.env.SYSTEM_ACCESSTOKEN: ${process.env.SYSTEM_ACCESSTOKEN ? "✅" : "❌"}\n
|
|
211
|
+
process.env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI: ${process.env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI ? "✅" : "❌"}\n
|
|
212
|
+
process.env.SYSTEM_TEAMPROJECTID: ${process.env.SYSTEM_TEAMPROJECTID ? "✅" : "❌"}\n
|
|
213
|
+
process.env.SYSTEM_PLANID: ${process.env.SYSTEM_PLANID ? "✅" : "❌"}\n
|
|
214
|
+
process.env.SYSTEM_JOBID: ${process.env.SYSTEM_JOBID ? "✅" : "❌"}\n
|
|
215
|
+
REMEMBER: process.env.SYSTEM_ACCESSTOKEN must be explicitly mapped!\n
|
|
216
|
+
https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken
|
|
217
|
+
`);
|
|
218
|
+
}
|
|
219
|
+
const oidcRequestUrl = `${teamFoundationCollectionUri}${teamProjectId}/_apis/distributedtask/hubs/build/plans/${planId}/jobs/${jobId}/oidctoken?api-version=7.1-preview.1&serviceConnectionId=${serviceConnectionId}`;
|
|
220
|
+
const { ClientAssertionCredential } = yield Promise.resolve().then(() => require("@azure/identity"));
|
|
221
|
+
return new ClientAssertionCredential(domain, clientId, () => __awaiter(this, void 0, void 0, function* () { return yield requestOidcToken(oidcRequestUrl, systemAccessToken); }));
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* API reference: https://learn.microsoft.com/en-us/rest/api/azure/devops/distributedtask/oidctoken/create
|
|
227
|
+
*/
|
|
228
|
+
function requestOidcToken(oidcRequestUrl, systemAccessToken) {
|
|
229
|
+
var _a;
|
|
230
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
231
|
+
const { ServiceClient } = yield Promise.resolve().then(() => require('@azure/core-client'));
|
|
232
|
+
const { createHttpHeaders, createPipelineRequest } = yield Promise.resolve().then(() => require('@azure/core-rest-pipeline'));
|
|
233
|
+
const genericClient = new ServiceClient();
|
|
234
|
+
const request = createPipelineRequest({
|
|
235
|
+
url: oidcRequestUrl,
|
|
236
|
+
method: "POST",
|
|
237
|
+
headers: createHttpHeaders({
|
|
238
|
+
"Content-Type": "application/json",
|
|
239
|
+
"Authorization": `Bearer ${systemAccessToken}`
|
|
240
|
+
})
|
|
241
|
+
});
|
|
242
|
+
const response = yield genericClient.sendRequest(request);
|
|
243
|
+
const body = ((_a = response.bodyAsText) === null || _a === void 0 ? void 0 : _a.toString()) || "";
|
|
244
|
+
if (response.status !== 200) {
|
|
245
|
+
throw new Error(`Failed to get OIDC token:\n
|
|
246
|
+
Response status: ${response.status}\n
|
|
247
|
+
Response body: ${body}\n
|
|
248
|
+
Response headers: ${JSON.stringify(response.headers.toJSON())}
|
|
249
|
+
`);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
console.log(`Successfully got OIDC token with status ${response.status}`);
|
|
253
|
+
}
|
|
254
|
+
return JSON.parse(body).oidcToken;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
257
|
//# sourceMappingURL=AzureDevOpsSubscriptionProvider.js.map
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
import type { TokenCredential } from '@azure/core-auth';
|
|
2
|
-
import type { Environment } from '@azure/ms-rest-azure-env';
|
|
3
|
-
import * as vscode from "vscode";
|
|
4
|
-
import { AzureAuthentication } from './AzureAuthentication';
|
|
5
|
-
/**
|
|
6
|
-
* A type representing an Azure subscription ID, not including the tenant ID.
|
|
7
|
-
*/
|
|
8
|
-
export type SubscriptionId = string;
|
|
9
|
-
/**
|
|
10
|
-
* A type representing an Azure tenant ID.
|
|
11
|
-
*/
|
|
12
|
-
export type TenantId = string;
|
|
13
|
-
/**
|
|
14
|
-
* Represents an Azure subscription.
|
|
15
|
-
*/
|
|
16
|
-
export interface AzureSubscription {
|
|
17
|
-
/**
|
|
18
|
-
* Access to the authentication session associated with this subscription.
|
|
19
|
-
*/
|
|
20
|
-
readonly authentication: AzureAuthentication;
|
|
21
|
-
/**
|
|
22
|
-
* The Azure environment to which this subscription belongs.
|
|
23
|
-
*/
|
|
24
|
-
readonly environment: Environment;
|
|
25
|
-
/**
|
|
26
|
-
* Whether this subscription belongs to a custom cloud.
|
|
27
|
-
*/
|
|
28
|
-
readonly isCustomCloud: boolean;
|
|
29
|
-
/**
|
|
30
|
-
* The display name of this subscription.
|
|
31
|
-
*/
|
|
32
|
-
readonly name: string;
|
|
33
|
-
/**
|
|
34
|
-
* The ID of this subscription.
|
|
35
|
-
*/
|
|
36
|
-
readonly subscriptionId: SubscriptionId;
|
|
37
|
-
/**
|
|
38
|
-
* The ID of the tenant to which this subscription belongs.
|
|
39
|
-
*/
|
|
40
|
-
readonly tenantId: TenantId;
|
|
41
|
-
/**
|
|
42
|
-
* The credential for authentication to this subscription. Compatible with Azure track 2 SDKs.
|
|
43
|
-
*/
|
|
44
|
-
readonly credential: TokenCredential;
|
|
45
|
-
/**
|
|
46
|
-
* The account associated with this subscription.
|
|
47
|
-
*/
|
|
48
|
-
readonly account: vscode.AuthenticationSessionAccountInformation;
|
|
49
|
-
}
|
|
1
|
+
import type { TokenCredential } from '@azure/core-auth';
|
|
2
|
+
import type { Environment } from '@azure/ms-rest-azure-env';
|
|
3
|
+
import * as vscode from "vscode";
|
|
4
|
+
import { AzureAuthentication } from './AzureAuthentication';
|
|
5
|
+
/**
|
|
6
|
+
* A type representing an Azure subscription ID, not including the tenant ID.
|
|
7
|
+
*/
|
|
8
|
+
export type SubscriptionId = string;
|
|
9
|
+
/**
|
|
10
|
+
* A type representing an Azure tenant ID.
|
|
11
|
+
*/
|
|
12
|
+
export type TenantId = string;
|
|
13
|
+
/**
|
|
14
|
+
* Represents an Azure subscription.
|
|
15
|
+
*/
|
|
16
|
+
export interface AzureSubscription {
|
|
17
|
+
/**
|
|
18
|
+
* Access to the authentication session associated with this subscription.
|
|
19
|
+
*/
|
|
20
|
+
readonly authentication: AzureAuthentication;
|
|
21
|
+
/**
|
|
22
|
+
* The Azure environment to which this subscription belongs.
|
|
23
|
+
*/
|
|
24
|
+
readonly environment: Environment;
|
|
25
|
+
/**
|
|
26
|
+
* Whether this subscription belongs to a custom cloud.
|
|
27
|
+
*/
|
|
28
|
+
readonly isCustomCloud: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The display name of this subscription.
|
|
31
|
+
*/
|
|
32
|
+
readonly name: string;
|
|
33
|
+
/**
|
|
34
|
+
* The ID of this subscription.
|
|
35
|
+
*/
|
|
36
|
+
readonly subscriptionId: SubscriptionId;
|
|
37
|
+
/**
|
|
38
|
+
* The ID of the tenant to which this subscription belongs.
|
|
39
|
+
*/
|
|
40
|
+
readonly tenantId: TenantId;
|
|
41
|
+
/**
|
|
42
|
+
* The credential for authentication to this subscription. Compatible with Azure track 2 SDKs.
|
|
43
|
+
*/
|
|
44
|
+
readonly credential: TokenCredential;
|
|
45
|
+
/**
|
|
46
|
+
* The account associated with this subscription.
|
|
47
|
+
*/
|
|
48
|
+
readonly account: vscode.AuthenticationSessionAccountInformation;
|
|
49
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*---------------------------------------------------------------------------------------------
|
|
3
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
-
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
-
*--------------------------------------------------------------------------------------------*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
//# sourceMappingURL=AzureSubscription.js.map
|