Skip to content

Commit 4df6532

Browse files
authored
Merge pull request #1157 from forcedotcom/sm/port-in-auth-url
feat: sfdxAuthUrl support port in instanceUrl
2 parents a471d1e + b82e1da commit 4df6532

File tree

2 files changed

+100
-43
lines changed

2 files changed

+100
-43
lines changed

src/org/authInfo.ts

+7-11
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ export class AuthInfo extends AsyncOptionalCreatable<AuthInfo.Options> {
363363
sfdxAuthUrl: string
364364
): Pick<AuthFields, 'clientId' | 'clientSecret' | 'refreshToken' | 'loginUrl'> {
365365
const match = sfdxAuthUrl.match(
366-
/^force:\/\/([a-zA-Z0-9._-]+={0,2}):([a-zA-Z0-9._-]*={0,2}):([a-zA-Z0-9._-]+={0,2})@([a-zA-Z0-9._-]+)/
366+
/^force:\/\/([a-zA-Z0-9._-]+={0,2}):([a-zA-Z0-9._-]*={0,2}):([a-zA-Z0-9._-]+={0,2})@([a-zA-Z0-9:._-]+)/
367367
);
368368

369369
if (!match) {
@@ -687,16 +687,12 @@ export class AuthInfo extends AsyncOptionalCreatable<AuthInfo.Options> {
687687
* **See** [SFDX Authorization](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_force_auth.htm#cli_reference_force_auth)
688688
*/
689689
public getSfdxAuthUrl(): string {
690-
const decryptedFields = this.getFields(true);
691-
const instanceUrl = ensure(decryptedFields.instanceUrl, 'undefined instanceUrl').replace(/^https?:\/\//, '');
692-
let sfdxAuthUrl = 'force://';
693-
694-
if (decryptedFields.clientId) {
695-
sfdxAuthUrl += `${decryptedFields.clientId}:${decryptedFields.clientSecret ?? ''}:`;
696-
}
697-
698-
sfdxAuthUrl += `${ensure(decryptedFields.refreshToken, 'undefined refreshToken')}@${instanceUrl}`;
699-
return sfdxAuthUrl;
690+
const { clientId, clientSecret, refreshToken, instanceUrl } = this.getFields(true);
691+
// host includes an optional port on the instanceUrl
692+
const url = new URL(ensure(instanceUrl, 'undefined instanceUrl')).host;
693+
const clientIdAndSecret = clientId ? `${clientId}:${clientSecret ?? ''}` : '';
694+
const token = ensure(refreshToken, 'undefined refreshToken');
695+
return `force://${clientIdAndSecret}:${token}@${url}`;
700696
}
701697

702698
/**

test/unit/org/authInfo.test.ts

+93-32
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import jwt from 'jsonwebtoken';
1515
import { env, includes } from '@salesforce/kit';
1616
import { spyMethod, stubMethod } from '@salesforce/ts-sinon';
1717
import { AnyJson, getJsonMap, JsonMap, toJsonMap } from '@salesforce/ts-types';
18-
import { expect } from 'chai';
18+
import { expect, config as chaiConfig } from 'chai';
1919
import { Transport } from '@jsforce/jsforce-node/lib/transport';
2020

2121
import { OAuth2 } from '@jsforce/jsforce-node';
@@ -34,6 +34,7 @@ import { SfdcUrl } from '../../../src/util/sfdcUrl';
3434
import * as suggestion from '../../../src/util/findSuggestion';
3535
import { SfError } from '../../../src';
3636

37+
chaiConfig.truncateThreshold = 0;
3738
class AuthInfoMockOrg extends MockTestOrgData {
3839
public privateKey = 'authInfoTest/jwt/server.key';
3940
public expirationDate = '12-02-20';
@@ -1273,13 +1274,15 @@ describe('AuthInfo', () => {
12731274
);
12741275
});
12751276

1276-
it('should handle undefined client secret', async () => {
1277+
it('should handle instance url with a port on it', async () => {
12771278
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
12781279
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();
12791280

1281+
const url = new URL(`${testOrg.instanceUrl}:6101`);
1282+
12801283
const authResponse = {
12811284
access_token: testOrg.accessToken,
1282-
instance_url: testOrg.instanceUrl,
1285+
instance_url: url.toString(),
12831286
id: '00DAuthInfoTest_orgId/005AuthInfoTest_userId',
12841287
};
12851288

@@ -1291,17 +1294,17 @@ describe('AuthInfo', () => {
12911294
username: testOrg.username,
12921295
oauth2Options: {
12931296
refreshToken: testOrg.refreshToken,
1294-
loginUrl: testOrg.loginUrl,
1297+
loginUrl: url.toString(),
12951298
},
12961299
});
12971300

1298-
// delete the client secret
1299-
authInfo.update({ clientSecret: undefined });
1300-
const instanceUrl = testOrg.instanceUrl.replace('https://', '');
1301-
expect(authInfo.getSfdxAuthUrl()).to.contain(`force://PlatformCLI::${testOrg.refreshToken}@${instanceUrl}`);
1301+
// host will include the port
1302+
const result = authInfo.getSfdxAuthUrl();
1303+
expect(result).to.contain(url.port);
1304+
expect(result).to.contain(url.host);
13021305
});
13031306

1304-
it('should handle undefined refresh token', async () => {
1307+
it('should handle undefined client secret', async () => {
13051308
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
13061309
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();
13071310

@@ -1323,37 +1326,67 @@ describe('AuthInfo', () => {
13231326
},
13241327
});
13251328

1326-
// delete the refresh token
1327-
authInfo.update({ ...authInfo.getFields(), refreshToken: undefined });
1328-
expect(() => authInfo.getSfdxAuthUrl()).to.throw('undefined refreshToken');
1329+
// delete the client secret
1330+
authInfo.update({ clientSecret: undefined });
1331+
const instanceUrl = testOrg.instanceUrl.replace('https://', '');
1332+
expect(authInfo.getSfdxAuthUrl()).to.contain(`force://PlatformCLI::${testOrg.refreshToken}@${instanceUrl}`);
13291333
});
13301334

1331-
it('should handle undefined instance url', async () => {
1332-
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
1333-
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();
1335+
describe('error conditions', () => {
1336+
it('should handle undefined refresh token', async () => {
1337+
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
1338+
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();
13341339

1335-
const authResponse = {
1336-
access_token: testOrg.accessToken,
1337-
instance_url: testOrg.instanceUrl,
1338-
id: '00DAuthInfoTest_orgId/005AuthInfoTest_userId',
1339-
};
1340+
const authResponse = {
1341+
access_token: testOrg.accessToken,
1342+
instance_url: testOrg.instanceUrl,
1343+
id: '00DAuthInfoTest_orgId/005AuthInfoTest_userId',
1344+
};
13401345

1341-
// Stub the http request (OAuth2.refreshToken())
1342-
postParamsStub.resolves(authResponse);
1346+
// Stub the http request (OAuth2.refreshToken())
1347+
postParamsStub.resolves(authResponse);
13431348

1344-
// Create the refresh token AuthInfo instance
1345-
const authInfo = await AuthInfo.create({
1346-
username: testOrg.username,
1347-
oauth2Options: {
1348-
refreshToken: testOrg.refreshToken,
1349-
loginUrl: testOrg.loginUrl,
1350-
},
1349+
// Create the refresh token AuthInfo instance
1350+
const authInfo = await AuthInfo.create({
1351+
username: testOrg.username,
1352+
oauth2Options: {
1353+
refreshToken: testOrg.refreshToken,
1354+
loginUrl: testOrg.loginUrl,
1355+
},
1356+
});
1357+
1358+
// delete the refresh token
1359+
authInfo.update({ ...authInfo.getFields(), refreshToken: undefined });
1360+
expect(() => authInfo.getSfdxAuthUrl()).to.throw('undefined refreshToken');
13511361
});
13521362

1353-
// delete the instance url
1354-
authInfo.update({ ...authInfo.getFields(), instanceUrl: undefined });
1363+
it('should handle undefined instance url', async () => {
1364+
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
1365+
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();
13551366

1356-
expect(() => authInfo.getSfdxAuthUrl()).to.throw('undefined instanceUrl');
1367+
const authResponse = {
1368+
access_token: testOrg.accessToken,
1369+
instance_url: testOrg.instanceUrl,
1370+
id: '00DAuthInfoTest_orgId/005AuthInfoTest_userId',
1371+
};
1372+
1373+
// Stub the http request (OAuth2.refreshToken())
1374+
postParamsStub.resolves(authResponse);
1375+
1376+
// Create the refresh token AuthInfo instance
1377+
const authInfo = await AuthInfo.create({
1378+
username: testOrg.username,
1379+
oauth2Options: {
1380+
refreshToken: testOrg.refreshToken,
1381+
loginUrl: testOrg.loginUrl,
1382+
},
1383+
});
1384+
1385+
// delete the instance url
1386+
authInfo.update({ ...authInfo.getFields(), instanceUrl: undefined });
1387+
1388+
expect(() => authInfo.getSfdxAuthUrl()).to.throw('undefined instanceUrl');
1389+
});
13571390
});
13581391
});
13591392

@@ -1703,6 +1736,19 @@ describe('AuthInfo', () => {
17031736
expect(options.loginUrl).to.equal('https://test.my.salesforce.com');
17041737
});
17051738

1739+
it('should parse the correct url with a port on the end', () => {
1740+
const options = AuthInfo.parseSfdxAuthUrl(
1741+
'force://PlatformCLI::5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYUB.@test.my.salesforce.com:6101'
1742+
);
1743+
1744+
expect(options.refreshToken).to.equal(
1745+
'5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYUB.'
1746+
);
1747+
expect(options.clientId).to.equal('PlatformCLI');
1748+
expect(options.clientSecret).to.equal('');
1749+
expect(options.loginUrl).to.equal('https://test.my.salesforce.com:6101');
1750+
});
1751+
17061752
it('should parse an id, secret, and token that include = for padding', () => {
17071753
const options = AuthInfo.parseSfdxAuthUrl(
17081754
'force://3MVG9SemV5D80oBfPBCgboxuJ9cOMLWNM1DDOZ8zgvJGsz13H3J66coUBCFF3N0zEgLYijlkqeWk4ot_Q2.4o=:438437816653243682==:5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYU==@test.my.salesforce.com'
@@ -1718,6 +1764,21 @@ describe('AuthInfo', () => {
17181764
expect(options.loginUrl).to.equal('https://test.my.salesforce.com');
17191765
});
17201766

1767+
it('should parse an id, secret, and token that include = for padding and a port', () => {
1768+
const options = AuthInfo.parseSfdxAuthUrl(
1769+
'force://3MVG9SemV5D80oBfPBCgboxuJ9cOMLWNM1DDOZ8zgvJGsz13H3J66coUBCFF3N0zEgLYijlkqeWk4ot_Q2.4o=:438437816653243682==:5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYU==@test.my.salesforce.com:6101'
1770+
);
1771+
1772+
expect(options.refreshToken).to.equal(
1773+
'5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYU=='
1774+
);
1775+
expect(options.clientId).to.equal(
1776+
'3MVG9SemV5D80oBfPBCgboxuJ9cOMLWNM1DDOZ8zgvJGsz13H3J66coUBCFF3N0zEgLYijlkqeWk4ot_Q2.4o='
1777+
);
1778+
expect(options.clientSecret).to.equal('438437816653243682==');
1779+
expect(options.loginUrl).to.equal('https://test.my.salesforce.com:6101');
1780+
});
1781+
17211782
it('should parse the correct url with client secret', () => {
17221783
const options = AuthInfo.parseSfdxAuthUrl(
17231784
'force://3MVG9SemV5D80oBfPBCgboxuJ9cOMLWNM1DDOZ8zgvJGsz13H3J66coUBCFF3N0zEgLYijlkqeWk4ot_Q2.4o:438437816653243682:5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYUB.@test.my.salesforce.com'

0 commit comments

Comments
 (0)