Skip to content

Commit 6b005a7

Browse files
Add login through federated identity for Azure Devops. Closes #6649
1 parent 195c8d5 commit 6b005a7

File tree

3 files changed

+320
-37
lines changed

3 files changed

+320
-37
lines changed

src/Auth.spec.ts

Lines changed: 220 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ describe('Auth', () => {
7171
const identityTenantId = '9bc3ab49-b65d-410a-85ad-de819febfddd';
7272
const appId = '9bc3ab49-b65d-410a-85ad-de819febfddc';
7373
const tenant = '9bc3ab49-b65d-410a-85ad-de819febfddd';
74+
const serviceConnectionId = 'cf54610a-5868-477c-b766-1ac6bd2ef63c';
75+
const serviceConnectionAppId = 'b5882c53-5488-4a65-9bdd-4c1754e7e8dd';
76+
const serviceConnectionTenantId = 'b11abebe-6eab-4e99-9571-b6f5433f9d5d';
7477
const federatedIdentityAudience = 'api://AzureADTokenExchange';
7578
const activeConnection: Connection = { name: identityId, identityId, identityName, active: true, appId, tenant, authType: AuthType.DeviceCode, certificateType: CertificateType.Unknown, accessTokens: {}, cloudType: CloudType.Public, identityTenantId: identityTenantId, deactivate: () => { } };
7679
const base64EncodedPemCert = 'QmFnIEF0dHJpYnV0ZXMNCiAgICBsb2NhbEtleUlEOiBDQyBGNCBGMiBBMyBDMyBEMiAwOSBDNSAxMiBCMyA3MiA0QiBCOCA4MyBBNSA0NyA0QyAwOSAyMSBEQyANCnN1YmplY3Q9QyA9IEFVLCBTVCA9IFNvbWUtU3RhdGUsIE8gPSBJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQNCg0KaXNzdWVyPUMgPSBBVSwgU1QgPSBTb21lLVN0YXRlLCBPID0gSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkDQoNCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQ0KTUlJRGF6Q0NBbE9nQXdJQkFnSVVXb25VNFM0RTcxRjVZMU5zU0xYbUlhZ1dkNVl3RFFZSktvWklodmNOQVFFTA0KQlFBd1JURUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeElUQWZCZ05WQkFvTQ0KR0VsdWRHVnlibVYwSUZkcFpHZHBkSE1nVUhSNUlFeDBaREFlRncweE9UQTNNVEl5TVRVek1qbGFGdzB5TURBMw0KTVRFeU1UVXpNamxhTUVVeEN6QUpCZ05WQkFZVEFrRlZNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFdw0KSHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXdnZ0VpTUEwR0NTcUdTSWIzRFFFQg0KQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUNsa01lQXlKbTJkMy95aEV0NHZGYjYrYjEyUGxRSDB4VGx1a1BoK2xScg0KOXJDNk5DM3dObnoySm5vbE1HclhuZVp2TlN5czFONVpSTm0yTjhQdy9QOExxeHJSenFFOFBNVC96NnN1UFhSUg0KWm5hZ2xaUklXb0NNR25pRVlDZVJHZnI4R2JpUXcwYlZEeXFuSnJaZjByS0pHbnZUNlY3QmpUdFloRWIzeXhoNA0KSmNUSnIrVDl0OEFYaldmemt6alBZdklxYmhha3FxcHd1SEVPYkh4T201cHVERTFBNVJOZm8wamcrTmZtVko5VQ0KMWR1RjVzdmE2NVQ5Q1RtdEdlbVNlUGlzWmgxZmhoOS94QmJwTCs0RUJWUXZqdEZXWk5zMVJHMW9QUllscmpzaQ0KTXFsaHNUdjhDZXI5cWUxcVNTdHFjMmJsc3hGek1zNmxZOHAvUHIrYm5uR3pBZ01CQUFHalV6QlJNQjBHQTFVZA0KRGdRV0JCU203cWFreXQwY2xxN0lnRFRWdkUrWEpaNFU5akFmQmdOVkhTTUVHREFXZ0JTbTdxYWt5dDBjbHE3SQ0KZ0RUVnZFK1hKWjRVOWpBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBYQ0KQnVqTytveU0yL0Q0SzNpS3lqVDVzbHF2UFVlVzFrZVVXYVdSVDZXRTY0VkFPbTlPZzU1bkIyOE5TSVVXampXMA0KdTJEUHF3SzJiOEFXalEveWp3S3NUMXVTdzcyQ0VEY2o3SkE1VXA5UWpBa0hIZmFoQWtOd0o5M0llcmFBdTEyVQ0KN25FRDdIN20yeGZscDVwM0dadzNHUE0rZmpBaDZLOUZIRDI0bWdGUTh4b2JPQSttVEVvV2ZIVVQrZ1pUMGxYdQ0KazFrVTJVelVOd2dwc3c4V04wNFFzWU5XcFF5d3ppUWtuZTQzNW5tdmxZOGZRc2hPSnErK0JCS0thd0xEcjk3bA0KRTBYQUxEZDZlVVhQenZ5OU1xZlozeUswRmUzMy8zbnZnUnE4QWZ3azRsbzhac2ZYWUlSTXA3b3BER0VmaUZmNQ0KM3JTTGxSZG9TNDQ4OVFZRnAyYUQNCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0NCkJhZyBBdHRyaWJ1dGVzDQogICAgbG9jYWxLZXlJRDogQ0MgRjQgRjIgQTMgQzMgRDIgMDkgQzUgMTIgQjMgNzIgNEIgQjggODMgQTUgNDcgNEMgMDkgMjEgREMgDQpLZXkgQXR0cmlidXRlczogPE5vIEF0dHJpYnV0ZXM+DQotLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS0NCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQ2xrTWVBeUptMmQzL3kNCmhFdDR2RmI2K2IxMlBsUUgweFRsdWtQaCtsUnI5ckM2TkMzd05uejJKbm9sTUdyWG5lWnZOU3lzMU41WlJObTINCk44UHcvUDhMcXhyUnpxRThQTVQvejZzdVBYUlJabmFnbFpSSVdvQ01HbmlFWUNlUkdmcjhHYmlRdzBiVkR5cW4NCkpyWmYwcktKR252VDZWN0JqVHRZaEViM3l4aDRKY1RKcitUOXQ4QVhqV2Z6a3pqUFl2SXFiaGFrcXFwd3VIRU8NCmJIeE9tNXB1REUxQTVSTmZvMGpnK05mbVZKOVUxZHVGNXN2YTY1VDlDVG10R2VtU2VQaXNaaDFmaGg5L3hCYnANCkwrNEVCVlF2anRGV1pOczFSRzFvUFJZbHJqc2lNcWxoc1R2OENlcjlxZTFxU1N0cWMyYmxzeEZ6TXM2bFk4cC8NClByK2Jubkd6QWdNQkFBRUNnZ0VBUjRsMytqZ3kybmxseWtiSlNXQ3ZnSCs2RWtZNkRxdHd3eFlwVUpIV09sUDcNCjVtaTNWS3htY0FFT0U5V0l4S05RTnNyV0E5TnlRMFlSZjc4MnBZRGJQcEp1NHlxUjFqSTN1SVJsWlhSZU52RzcNCjNnVGpiaVBVbVRTeTBCZXY0TzFGMmZuUEdwV1ZuR2VTT1dqcnNobWExTXlocGwyV2VMRHFiSU96R2t3aHhYOXkNClRhRFd5MjErbDFpNVNGWUZTdHdXOWlhOXRORTFTTTU4WnpQWk0yK0NDdHhQVEFBQXRJRmZXUVdTbnhodUxMenMNCjNyVDRVOGNLZzJITVBXb29rOS9peWxsa0xEVXBPanhJR2tHWXdheDVnR2xvR0xZYWVoelc5Q3hobzgvc3A4WjUNCkVNNVFvczVJSTF2K21pNHhHa0RTdW4rbDYzcDN5Nm54T3pqM1h1MzRlUUtCZ1FEUDNtRWttN2lVaTlhRUxweXYNCkIxeDFlRFR2UmEwcllZMHZUaXFrYzhyUGc0NU1uOUNWRWZqdnV3YkN4M21tTExabThqZVY3ZTFHWjZJeXYreEUNCmcxeFkrUTd0RUlCb1FwWThlemg0UVYvMXRkZkhiUzNPcGdIbHVqMGd5MWxqT2QrbkxzS2RNQWRlYVF3Uy9WK2MNCk51Sks0Y3oyQWl6UXU1dHQ4WHdoOGdvU0Z3S0JnUURMNXRjZnF0VmdMQWJmMnJQbEhBLzdNcU1sWGpqNUQ0ejkNCjZmTWlCVDdOWHlYUGx6a2pJQkxOdG9OWlBCVTFzeERFb2tiNUtyTlhLTUtIaU9nTkQ0cWtDYkdnRFk2WUdaS3cNCkg4bDlLWDBaM2pwcEp0TURvQ21yQW9hSmZTUXNreGJXSDd4VlFGVzdPVWQ0dHMxZ3FDbTBUTFVxeW9lcW1EK3INCmg3WFlaa2RxeFFLQmdBK2NpZnN2M3NyNVBhRXJ4d1MyTHRGN3Q2NElzNXJBZHRRSXNOY3RBeHhXcXdkQ01XNGcNCnJXdUR4bHcya3dKUjlWa0I4LzdFb2I5WjVTcWVrMllKMzVPbkVPSHBEVnZITkhWU1k4bFVUNXFxajR3Z3ZRSDYNCkljWlpHR0l3STRSNlFqdlNIVGVrOWNpM1p2cStJTUlndFJvZW4wQVNwYjcvZUFybnlnVGFvcnI5QW9HQkFJT3QNCllOSEhqaUtjYkJnV2NjU01tZGw4T3hXL3dvVTlRSzBkYjNGUjk5dkREWFVCVU5uWk5hdDVxVnR3VExZd0hLMFANCnEwdndBbjlRQ0VoazVvN0FzYVQ3eWFUMS9GZEhkSTZmQ0l6MnhSNTJnRHcxNFdIZkJlbTFLTk1UYU5BTWNWdjQNCmhMUjlacUFRL3BIN1k2aC9FT2VwL2ZsVGI4ZUFxT1dLTDZvL2F2R05Bb0dCQUlHc0c1VExuSmlPU044SUtGU04NCmJmK3IrNkhWL2R6MkluNjhSR255MTB0OGpwbUpPbGgrdXRncGtvOXI2Y09uWGY4VHM2SFAveTBtbDl5YXhvMlANCm52c2wwcFlseFQxQy9taXJaZWxYKzFaQTltdFpHT2RxbzZhdVZUM1drcXBpb3c2WUtzbzl2Z2RHWmRWRUxiMEINCnUvdyt4UjBvN21aSEpwVEdmS09KdE53MQ0KLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQ0K';
@@ -129,6 +132,7 @@ describe('Auth', () => {
129132
sinonUtil.restore([
130133
cli.getConfig().get,
131134
request.get,
135+
request.post,
132136
(auth as any).getClientApplication,
133137
(auth as any).getDeviceCodeResponse,
134138
(auth as any).storeConnectionInfo,
@@ -1404,12 +1408,8 @@ describe('Auth', () => {
14041408
if (opts.url === `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`) {
14051409
return {
14061410
"access_token": accessToken,
1407-
"client_id": "a04566df-9a65-4e90-ae3d-574572a16423",
1408-
"expires_in": "86399",
1409-
"expires_on": "1587847593",
1410-
"ext_expires_in": "86399",
1411-
"not_before": "1587760893",
1412-
"resource": "https://contoso.sharepoint.com/",
1411+
"expires_in": "3599",
1412+
"ext_expires_in": "3599",
14131413
"token_type": "Bearer"
14141414
};
14151415
}
@@ -1430,17 +1430,228 @@ describe('Auth', () => {
14301430
assert.strictEqual(requestPostStub.firstCall.args[0].data.indexOf(`client_assertion=${federatedIdentityClientAssertion}`) > -1, true);
14311431
});
14321432

1433-
it('fails when not using federated identity from GitHub Action', async () => {
1433+
it('calls api with correct params using federated identity flow from Azure DevOps Pipeline without Service Connection', async () => {
1434+
process.env = {
1435+
SYSTEM_OIDCREQUESTURI: 'https://contoso.visualstudio.com/0d0a69da-77db-472d-9e84-8beb80d4de42/_apis/distributedtask/hubs/build/plans/dec90b47-fb8f-4dad-8ef3-4e06ae1ca4ab/jobs/037420a7-9ab4-4003-8520-087b4b4a80b7/oidctoken',
1436+
SYSTEM_ACCESSTOKEN: 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationToken-...'
1437+
};
1438+
const federatedIdentityClientAssertion = 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationClientAssertion-...';
1439+
const accessToken = 'eyJ0eXAiOiJKV1QiLCJ-EntraIDAccessToken...';
1440+
1441+
const requestPostStub = sinon.stub(request, 'post').callsFake(async (opts) => {
1442+
if (opts.url === `${process.env.SYSTEM_OIDCREQUESTURI}?api-version=7.1`) {
1443+
return {
1444+
"oidcToken": federatedIdentityClientAssertion
1445+
};
1446+
}
1447+
else if (opts.url === `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`) {
1448+
return {
1449+
"access_token": accessToken,
1450+
"expires_in": "3599",
1451+
"ext_expires_in": "3599",
1452+
"token_type": "Bearer"
1453+
};
1454+
}
1455+
1456+
throw { error: { "error": "Invalid POST Request" } };
1457+
});
1458+
1459+
auth.connection.authType = AuthType.FederatedIdentity;
1460+
auth.connection.appId = appId;
1461+
auth.connection.tenant = tenant;
1462+
1463+
const ensuredAccessToken = await auth.ensureAccessToken(resource, logger, true);
1464+
assert.strictEqual(ensuredAccessToken, accessToken);
1465+
assert.strictEqual(requestPostStub.firstCall.args[0].headers?.Authorization, `Bearer ${process.env.SYSTEM_ACCESSTOKEN}`);
1466+
assert(requestPostStub.calledTwice);
1467+
assert.strictEqual(requestPostStub.secondCall.args[0].data.indexOf(`client_id=${appId}`) > -1, true);
1468+
assert.strictEqual(requestPostStub.secondCall.args[0].data.indexOf(`client_assertion=${federatedIdentityClientAssertion}`) > -1, true);
1469+
});
1470+
1471+
it('calls api with correct params using federated identity flow from Azure DevOps Pipeline with Service Connection', async () => {
1472+
process.env = {
1473+
SYSTEM_OIDCREQUESTURI: 'https://contoso.visualstudio.com/0d0a69da-77db-472d-9e84-8beb80d4de42/_apis/distributedtask/hubs/build/plans/dec90b47-fb8f-4dad-8ef3-4e06ae1ca4ab/jobs/037420a7-9ab4-4003-8520-087b4b4a80b7/oidctoken',
1474+
SYSTEM_ACCESSTOKEN: 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationToken-...',
1475+
AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: serviceConnectionId,
1476+
AZURESUBSCRIPTION_CLIENT_ID: serviceConnectionAppId,
1477+
AZURESUBSCRIPTION_TENANT_ID: serviceConnectionTenantId
1478+
};
1479+
const federatedIdentityClientAssertion = 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationClientAssertion-...';
1480+
const accessToken = 'eyJ0eXAiOiJKV1QiLCJ-EntraIDAccessToken...';
1481+
1482+
const requestPostStub = sinon.stub(request, 'post').callsFake(async (opts) => {
1483+
if (opts.url === `${process.env.SYSTEM_OIDCREQUESTURI}?api-version=7.1&serviceConnectionId=${serviceConnectionId}`) {
1484+
return {
1485+
"oidcToken": federatedIdentityClientAssertion
1486+
};
1487+
}
1488+
else if (opts.url === `https://login.microsoftonline.com/${serviceConnectionTenantId}/oauth2/v2.0/token`) {
1489+
return {
1490+
"access_token": accessToken,
1491+
"expires_in": "3599",
1492+
"ext_expires_in": "3599",
1493+
"token_type": "Bearer"
1494+
};
1495+
}
1496+
1497+
throw { error: { "error": "Invalid POST Request" } };
1498+
});
1499+
1500+
auth.connection.authType = AuthType.FederatedIdentity;
1501+
1502+
const ensuredAccessToken = await auth.ensureAccessToken(resource, logger, true);
1503+
assert.strictEqual(ensuredAccessToken, accessToken);
1504+
assert.strictEqual(requestPostStub.firstCall.args[0].headers?.Authorization, `Bearer ${process.env.SYSTEM_ACCESSTOKEN}`);
1505+
assert(requestPostStub.calledTwice);
1506+
assert.strictEqual(requestPostStub.secondCall.args[0].data.indexOf(`client_id=${serviceConnectionAppId}`) > -1, true);
1507+
assert.strictEqual(requestPostStub.secondCall.args[0].data.indexOf(`client_assertion=${federatedIdentityClientAssertion}`) > -1, true);
1508+
});
1509+
1510+
it('calls api with correct params using federated identity flow from Azure DevOps Pipeline with Service Connection, overriding appId option', async () => {
1511+
process.env = {
1512+
SYSTEM_OIDCREQUESTURI: 'https://contoso.visualstudio.com/0d0a69da-77db-472d-9e84-8beb80d4de42/_apis/distributedtask/hubs/build/plans/dec90b47-fb8f-4dad-8ef3-4e06ae1ca4ab/jobs/037420a7-9ab4-4003-8520-087b4b4a80b7/oidctoken',
1513+
SYSTEM_ACCESSTOKEN: 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationToken-...',
1514+
AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: serviceConnectionId,
1515+
AZURESUBSCRIPTION_CLIENT_ID: serviceConnectionAppId,
1516+
AZURESUBSCRIPTION_TENANT_ID: serviceConnectionTenantId
1517+
};
1518+
const federatedIdentityClientAssertion = 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationClientAssertion-...';
1519+
const accessToken = 'eyJ0eXAiOiJKV1QiLCJ-EntraIDAccessToken...';
1520+
1521+
const requestPostStub = sinon.stub(request, 'post').callsFake(async (opts) => {
1522+
if (opts.url === `${process.env.SYSTEM_OIDCREQUESTURI}?api-version=7.1&serviceConnectionId=${serviceConnectionId}`) {
1523+
return {
1524+
"oidcToken": federatedIdentityClientAssertion
1525+
};
1526+
}
1527+
else if (opts.url === `https://login.microsoftonline.com/${serviceConnectionTenantId}/oauth2/v2.0/token`) {
1528+
return {
1529+
"access_token": accessToken,
1530+
"expires_in": "3599",
1531+
"ext_expires_in": "3599",
1532+
"token_type": "Bearer"
1533+
};
1534+
}
1535+
1536+
throw { error: { "error": "Invalid POST Request" } };
1537+
});
1538+
1539+
auth.connection.authType = AuthType.FederatedIdentity;
1540+
auth.connection.appId = appId;
1541+
1542+
const ensuredAccessToken = await auth.ensureAccessToken(resource, logger, true);
1543+
assert.strictEqual(ensuredAccessToken, accessToken);
1544+
assert.strictEqual(requestPostStub.firstCall.args[0].headers?.Authorization, `Bearer ${process.env.SYSTEM_ACCESSTOKEN}`);
1545+
assert(requestPostStub.calledTwice);
1546+
assert.strictEqual(requestPostStub.secondCall.args[0].data.indexOf(`client_id=${serviceConnectionAppId}`) > -1, true);
1547+
assert.strictEqual(requestPostStub.secondCall.args[0].data.indexOf(`client_assertion=${federatedIdentityClientAssertion}`) > -1, true);
1548+
});
1549+
1550+
it('calls api with correct params using federated identity flow from Azure DevOps Pipeline with Service Connection, overriding tenant option', async () => {
1551+
process.env = {
1552+
SYSTEM_OIDCREQUESTURI: 'https://contoso.visualstudio.com/0d0a69da-77db-472d-9e84-8beb80d4de42/_apis/distributedtask/hubs/build/plans/dec90b47-fb8f-4dad-8ef3-4e06ae1ca4ab/jobs/037420a7-9ab4-4003-8520-087b4b4a80b7/oidctoken',
1553+
SYSTEM_ACCESSTOKEN: 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationToken-...',
1554+
AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: serviceConnectionId,
1555+
AZURESUBSCRIPTION_CLIENT_ID: serviceConnectionAppId,
1556+
AZURESUBSCRIPTION_TENANT_ID: serviceConnectionTenantId
1557+
};
1558+
const federatedIdentityClientAssertion = 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationClientAssertion-...';
1559+
const accessToken = 'eyJ0eXAiOiJKV1QiLCJ-EntraIDAccessToken...';
1560+
1561+
const requestPostStub = sinon.stub(request, 'post').callsFake(async (opts) => {
1562+
if (opts.url === `${process.env.SYSTEM_OIDCREQUESTURI}?api-version=7.1&serviceConnectionId=${serviceConnectionId}`) {
1563+
return {
1564+
"oidcToken": federatedIdentityClientAssertion
1565+
};
1566+
}
1567+
else if (opts.url === `https://login.microsoftonline.com/${serviceConnectionTenantId}/oauth2/v2.0/token`) {
1568+
return {
1569+
"access_token": accessToken,
1570+
"expires_in": "3599",
1571+
"ext_expires_in": "3599",
1572+
"token_type": "Bearer"
1573+
};
1574+
}
1575+
1576+
throw { error: { "error": "Invalid POST Request" } };
1577+
});
1578+
1579+
auth.connection.authType = AuthType.FederatedIdentity;
1580+
auth.connection.appId = '';
1581+
auth.connection.tenant = tenant;
1582+
1583+
const ensuredAccessToken = await auth.ensureAccessToken(resource, logger, true);
1584+
assert.strictEqual(ensuredAccessToken, accessToken);
1585+
assert.strictEqual(requestPostStub.firstCall.args[0].headers?.Authorization, `Bearer ${process.env.SYSTEM_ACCESSTOKEN}`);
1586+
assert(requestPostStub.calledTwice);
1587+
assert.strictEqual(requestPostStub.secondCall.args[0].data.indexOf(`client_id=${serviceConnectionAppId}`) > -1, true);
1588+
assert.strictEqual(requestPostStub.secondCall.args[0].data.indexOf(`client_assertion=${federatedIdentityClientAssertion}`) > -1, true);
1589+
});
1590+
1591+
it('fails when not using federated identity from GitHub Action or Azure DevOps Pipeline', async () => {
14341592
process.env = {
14351593
ACTIONS_ID_TOKEN_REQUEST_URL: '',
1436-
ACTIONS_ID_TOKEN_REQUEST_TOKEN: ''
1594+
ACTIONS_ID_TOKEN_REQUEST_TOKEN: '',
1595+
SYSTEM_OIDCREQUESTURI: '',
1596+
SYSTEM_ACCESSTOKEN: ''
14371597
};
14381598

14391599
auth.connection.authType = AuthType.FederatedIdentity;
14401600
auth.connection.appId = appId;
14411601
auth.connection.tenant = tenant;
14421602

1443-
await assert.rejects(auth.ensureAccessToken(resource, logger, true), new CommandError('Federated identity is currently only supported in GitHub Actions.'));
1603+
await assert.rejects(auth.ensureAccessToken(resource, logger, true), new CommandError('Federated identity is currently only supported in GitHub Actions and Azure DevOps.'));
1604+
});
1605+
1606+
it('fails when using federated identity from Azure DevOps Pipeline, but SYSTEM_ACCESSTOKEN not available', async () => {
1607+
process.env = {
1608+
SYSTEM_OIDCREQUESTURI: 'https://contoso.visualstudio.com/0d0a69da-77db-472d-9e84-8beb80d4de42/_apis/distributedtask/hubs/build/plans/dec90b47-fb8f-4dad-8ef3-4e06ae1ca4ab/jobs/037420a7-9ab4-4003-8520-087b4b4a80b7/oidctoken',
1609+
SYSTEM_ACCESSTOKEN: ''
1610+
};
1611+
1612+
auth.connection.authType = AuthType.FederatedIdentity;
1613+
auth.connection.appId = appId;
1614+
auth.connection.tenant = tenant;
1615+
1616+
await assert.rejects(auth.ensureAccessToken(resource, logger, true), new CommandError(`The SYSTEM_ACCESSTOKEN environment variable is not available. Please check the Azure DevOps pipeline task configuration. It should contain 'SYSTEM_ACCESSTOKEN: $(System.AccessToken)' in the env section.`));
1617+
});
1618+
1619+
it('fails when using federated identity from Azure DevOps Pipeline without using service connection, with empty appId and tenant option', async () => {
1620+
process.env = {
1621+
SYSTEM_OIDCREQUESTURI: 'https://contoso.visualstudio.com/0d0a69da-77db-472d-9e84-8beb80d4de42/_apis/distributedtask/hubs/build/plans/dec90b47-fb8f-4dad-8ef3-4e06ae1ca4ab/jobs/037420a7-9ab4-4003-8520-087b4b4a80b7/oidctoken',
1622+
SYSTEM_ACCESSTOKEN: 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationToken-...'
1623+
};
1624+
1625+
auth.connection.authType = AuthType.FederatedIdentity;
1626+
auth.connection.appId = undefined;
1627+
auth.connection.tenant = 'common';
1628+
1629+
await assert.rejects(auth.ensureAccessToken(resource, logger, true), new CommandError(`The appId and tenant parameters are required when not using a service connection.`));
1630+
});
1631+
1632+
it('fails when using federated identity from Azure DevOps Pipeline without using service connection, with empty appId option', async () => {
1633+
process.env = {
1634+
SYSTEM_OIDCREQUESTURI: 'https://contoso.visualstudio.com/0d0a69da-77db-472d-9e84-8beb80d4de42/_apis/distributedtask/hubs/build/plans/dec90b47-fb8f-4dad-8ef3-4e06ae1ca4ab/jobs/037420a7-9ab4-4003-8520-087b4b4a80b7/oidctoken',
1635+
SYSTEM_ACCESSTOKEN: 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationToken-...'
1636+
};
1637+
1638+
auth.connection.authType = AuthType.FederatedIdentity;
1639+
auth.connection.tenant = 'common';
1640+
1641+
await assert.rejects(auth.ensureAccessToken(resource, logger, true), new CommandError(`The appId and tenant parameters are required when not using a service connection.`));
1642+
});
1643+
1644+
it('fails when using federated identity from Azure DevOps Pipeline without using service connection, with empty tenant option', async () => {
1645+
process.env = {
1646+
SYSTEM_OIDCREQUESTURI: 'https://contoso.visualstudio.com/0d0a69da-77db-472d-9e84-8beb80d4de42/_apis/distributedtask/hubs/build/plans/dec90b47-fb8f-4dad-8ef3-4e06ae1ca4ab/jobs/037420a7-9ab4-4003-8520-087b4b4a80b7/oidctoken',
1647+
SYSTEM_ACCESSTOKEN: 'eyJ0eXAiOiJKV1QiLCJ-DevOpsFederationToken-...'
1648+
};
1649+
1650+
auth.connection.authType = AuthType.FederatedIdentity;
1651+
auth.connection.appId = appId;
1652+
auth.connection.tenant = 'common';
1653+
1654+
await assert.rejects(auth.ensureAccessToken(resource, logger, true), new CommandError(`The appId and tenant parameters are required when not using a service connection.`));
14441655
});
14451656

14461657
it('returns access token if persisting connection fails', async () => {

0 commit comments

Comments
 (0)