Skip to content

Commit

Permalink
Merge pull request #81 from salesforcecli/re/sfdxAuthStoreJsonFile
Browse files Browse the repository at this point in the history
  • Loading branch information
RodEsp authored Mar 17, 2021
2 parents d09b38b + 5b6f898 commit 1b076d7
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 29 deletions.
46 changes: 26 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,21 @@ sfdx plugins
# Commands

<!-- commands -->
* [`sfdx auth:device:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authdevicelogin--i-string--r-url--d--s--a-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
* [`sfdx auth:jwt:grant -u <string> -f <filepath> -i <string> [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authjwtgrant--u-string--f-filepath--i-string--r-url--d--s--a-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
* [`sfdx auth:list [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authlist---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
* [`sfdx auth:logout [-a] [-p] [-u <string>] [--apiversion <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authlogout--a--p--u-string---apiversion-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
* [`sfdx auth:sfdxurl:store -f <filepath> [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authsfdxurlstore--f-filepath--d--s--a-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
* [`sfdx auth:web:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authweblogin--i-string--r-url--d--s--a-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)

- [`sfdx auth:device:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authdevicelogin--i-string--r-url--d--s--a-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
- [`sfdx auth:jwt:grant -u <string> -f <filepath> -i <string> [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authjwtgrant--u-string--f-filepath--i-string--r-url--d--s--a-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
- [`sfdx auth:list [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authlist---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
- [`sfdx auth:logout [-a] [-p] [-u <string>] [--apiversion <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authlogout--a--p--u-string---apiversion-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
- [`sfdx auth:sfdxurl:store -f <filepath> [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authsfdxurlstore--f-filepath--d--s--a-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)
- [`sfdx auth:web:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`](#sfdx-authweblogin--i-string--r-url--d--s--a-string---json---loglevel-tracedebuginfowarnerrorfataltracedebuginfowarnerrorfatal)

## `sfdx auth:device:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]`

authorize an org using a device code

```
USAGE
$ sfdx auth:device:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel
$ sfdx auth:device:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel
trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]
OPTIONS
Expand Down Expand Up @@ -125,7 +126,7 @@ authorize an org using the JWT flow

```
USAGE
$ sfdx auth:jwt:grant -u <string> -f <filepath> -i <string> [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel
$ sfdx auth:jwt:grant -u <string> -f <filepath> -i <string> [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel
trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]
OPTIONS
Expand Down Expand Up @@ -158,8 +159,8 @@ OPTIONS
DESCRIPTION
Use a certificate associated with your private key that has been uploaded to a personal connected app.
If you specify an --instanceurl value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To
specify a My Domain URL, use the format MyDomainName.my.salesforce.com (not MyDomainName.lightning.force.com). To
If you specify an --instanceurl value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To
specify a My Domain URL, use the format MyDomainName.my.salesforce.com (not MyDomainName.lightning.force.com). To
specify a sandbox, set --instanceurl to https://test.salesforce.com.
ALIASES
Expand Down Expand Up @@ -199,7 +200,7 @@ log out from authorized orgs

```
USAGE
$ sfdx auth:logout [-a] [-p] [-u <string>] [--apiversion <string>] [--json] [--loglevel
$ sfdx auth:logout [-a] [-p] [-u <string>] [--apiversion <string>] [--json] [--loglevel
trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]
OPTIONS
Expand Down Expand Up @@ -237,7 +238,7 @@ authorize an org using an SFDX auth URL

```
USAGE
$ sfdx auth:sfdxurl:store -f <filepath> [-d] [-s] [-a <string>] [--json] [--loglevel
$ sfdx auth:sfdxurl:store -f <filepath> [-d] [-s] [-a <string>] [--json] [--loglevel
trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]
OPTIONS
Expand All @@ -261,12 +262,16 @@ OPTIONS
this command invocation
DESCRIPTION
Authorize a Salesforce org using an SFDX auth URL stored within a file. The file must have the format
"force://<refreshToken>@<instanceUrl>" or "force://<clientId>:<clientSecret>:<refreshToken>@<instanceUrl>".
The file must contain only the URL or be a JSON file that has a top-level property named sfdxAuthUrl.
Use this command to get the SFDX auth URL for a Dev Hub org you have already authorized:
Authorize a Salesforce org using an SFDX auth URL stored within a file. The URL must have the format "force://<refreshToken>@<instanceUrl>" or "force://<clientId>:<clientSecret>:<refreshToken>@<instanceUrl>".
You have three options when creating the auth file. The easiest option is to redirect the output of the `sfdx force:org:display --verbose --json` command into a file.
For example, using an org you have already authorized:
$ sfdx force:org:display -u <DevHub> --verbose --json > authFile.json
$ sfdx auth:sfdxurl:store -f authFile.json
$ sfdx force:org:display -u <DevHub> --verbose
The resulting JSON file contains the URL in the sfdxAuthUrl property inside of a results object.
You can also create a JSON file that has a top-level property named sfdxAuthUrl whose value is the auth URL.
Finally, you can create a normal text file that includes just the URL and nothing else.
ALIASES
$ sfdx force:auth:sfdxurl:store
Expand All @@ -284,7 +289,7 @@ authorize an org using the web login flow

```
USAGE
$ sfdx auth:web:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel
$ sfdx auth:web:login [-i <string>] [-r <url>] [-d] [-s] [-a <string>] [--json] [--loglevel
trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]
OPTIONS
Expand All @@ -311,8 +316,8 @@ OPTIONS
this command invocation
DESCRIPTION
If you specify an --instanceurl value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To
specify a My Domain URL, use the format MyDomainName.my.salesforce.com (not MyDomainName.lightning.force.com). To log
If you specify an --instanceurl value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To
specify a My Domain URL, use the format MyDomainName.my.salesforce.com (not MyDomainName.lightning.force.com). To log
in to a sandbox, set --instanceurl to https://test.salesforce.com.
ALIASES
Expand All @@ -325,4 +330,5 @@ EXAMPLES
```

_See code: [src/commands/auth/web/login.ts](https://github.com/salesforcecli/plugin-auth/blob/v1.4.10/src/commands/auth/web/login.ts)_

<!-- commandsstop -->
2 changes: 1 addition & 1 deletion messages/sfdxurl.store.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"description": "authorize an org using an SFDX auth URL\nAuthorize a Salesforce org using an SFDX auth URL stored within a file. The file must have the format \"%s\" or \"%s\".\nThe file must contain only the URL or be a JSON file that has a top-level property named sfdxAuthUrl.\nUse this command to get the SFDX auth URL for a Dev Hub org you have already authorized:\n\n $ sfdx force:org:display -u <DevHub> --verbose",
"description": "Authorize an org using an SFDX auth URL\nAuthorize a Salesforce org using an SFDX auth URL stored within a file. The URL must have the format \"%s\" or \"%s\".\nYou have three options when creating the auth file. The easiest option is to redirect the output of the `sfdx force:org:display --verbose --json` command into a file.\nFor example, using an org you have already authorized:\n\n $ sfdx force:org:display -u <DevHub> --verbose --json > authFile.json\n $ sfdx auth:sfdxurl:store -f authFile.json\n\nThe resulting JSON file contains the URL in the sfdxAuthUrl property inside of a results object.\nYou can also create a JSON file that has a top-level property named sfdxAuthUrl whose value is the auth URL.\nFinally, you can create a normal text file that includes just the URL and nothing else.",
"file": "path to a file containing the sfdx url",
"examples": [
"sfdx auth:sfdxurl:store -f <path to sfdxAuthUrl file>",
Expand Down
29 changes: 27 additions & 2 deletions src/commands/auth/sfdxurl/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import * as os from 'os';
import { flags, FlagsConfig, SfdxCommand } from '@salesforce/command';
import { AuthFields, AuthInfo, fs, Messages } from '@salesforce/core';
import { AnyJson } from '@salesforce/ts-types';
import { Prompts } from '../../../prompts';
import { Common } from '../../../common';

Expand All @@ -18,6 +19,10 @@ const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'message
const AUTH_URL_FORMAT1 = 'force://<refreshToken>@<instanceUrl>';
const AUTH_URL_FORMAT2 = 'force://<clientId>:<clientSecret>:<refreshToken>@<instanceUrl>';

type AuthJson = AnyJson & {
result?: AnyJson & { sfdxAuthUrl: string };
sfdxAuthUrl: string;
};
export default class Store extends SfdxCommand {
public static readonly description = messages.getMessage('description', [AUTH_URL_FORMAT1, AUTH_URL_FORMAT2]);
public static readonly examples = messages.getMessage('examples').split(os.EOL);
Expand Down Expand Up @@ -52,8 +57,23 @@ export default class Store extends SfdxCommand {
public async run(): Promise<AuthFields> {
if (await Prompts.shouldExitCommand(this.ux, this.flags.noprompt)) return {};

const sfdxAuthUrl = await fs.readFile(this.flags.sfdxurlfile, 'utf8');
const oauth2Options = AuthInfo.parseSfdxAuthUrl(sfdxAuthUrl);
const authFile = this.flags.sfdxurlfile as string;

const sfdxAuthUrl = authFile.endsWith('.json')
? await this.getUrlFromJson(authFile)
: await fs.readFile(authFile, 'utf8');

let oauth2Options: AuthFields;
try {
oauth2Options = AuthInfo.parseSfdxAuthUrl(sfdxAuthUrl);
} catch (e) {
this.ux.error(
`Error getting the auth URL from file ${authFile}. Please ensure it meets the description shown in the documentation for this command.`
);
this.ux.error(this.statics.description);
return;
}

const authInfo = await AuthInfo.create({ oauth2Options });
await authInfo.save();

Expand All @@ -64,4 +84,9 @@ export default class Store extends SfdxCommand {
this.ux.log(successMsg);
return result;
}

private async getUrlFromJson(authFile: string): Promise<string> {
const authFileJson = (await fs.readJson(authFile)) as AuthJson;
return authFileJson.result?.sfdxAuthUrl || authFileJson.sfdxAuthUrl;
}
}
4 changes: 1 addition & 3 deletions test/commands/auth/device/login.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable camelcase */

import * as os from 'os';

import { $$, expect, test } from '@salesforce/command/lib/test';
import { AuthFields, AuthInfo } from '@salesforce/core';
import { MockTestOrgData } from '@salesforce/core/lib/testSetup';
Expand Down Expand Up @@ -38,7 +36,7 @@ interface Response {
}

function parseJsonResponse(str: string): [Action, Response] {
return str.split(`}${os.EOL}{`).map((p) => {
return str.split('}\n{').map((p) => {
if (p.startsWith('{')) {
return JSON.parse(`${p}}`) as Action;
} else {
Expand Down
41 changes: 38 additions & 3 deletions test/commands/auth/sfdxurl/store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ describe('auth:sfdxurl:store', async () => {
});

if (!options.fileDoesNotExist) {
$$.SANDBOX.stub(fs, 'readFile').callsFake(async () => {
return 'force://PlatformCLI::CoffeeAndBacon@su0503.my.salesforce.com';
});
$$.SANDBOX.stub(fs, 'readFile').callsFake(
async () => 'force://PlatformCLI::CoffeeAndBacon@su0503.my.salesforce.com'
);
}

if (options.authInfoCreateFails) {
Expand All @@ -58,6 +58,41 @@ describe('auth:sfdxurl:store', async () => {
expect(response.result.username).to.equal(testData.username);
});

test
.do(async () => {
await prepareStubs({ fileDoesNotExist: true });
$$.SANDBOX.stub(fs, 'readJson').callsFake(async () => ({
sfdxAuthUrl: 'force://PlatformCLI::CoffeeAndBacon@su0503.my.salesforce.com',
}));
})
.stdout()
.command(['auth:sfdxurl:store', '-f', 'path/to/key.json', '--json'])
.it('should return auth fields when passing in a json file', (ctx) => {
const response = parseJson<AuthFields>(ctx.stdout);
expect(response.status).to.equal(0);
expect(response.result).to.deep.equal(authFields);
expect(response.result.username).to.equal(testData.username);
});

test
.do(async () => {
await prepareStubs({ fileDoesNotExist: true });
$$.SANDBOX.stub(fs, 'readJson').callsFake(async () => ({
result: { sfdxAuthUrl: 'force://PlatformCLI::CoffeeAndBacon@su0503.my.salesforce.com' },
}));
})
.stdout()
.command(['auth:sfdxurl:store', '-f', 'path/to/key.json', '--json'])
.it(
'should return auth fields when passing in a json result a la `sfdx force:org:display --verbose --json`',
(ctx) => {
const response = parseJson<AuthFields>(ctx.stdout);
expect(response.status).to.equal(0);
expect(response.result).to.deep.equal(authFields);
expect(response.result.username).to.equal(testData.username);
}
);

test
.do(async () => prepareStubs())
.stdout()
Expand Down

0 comments on commit 1b076d7

Please sign in to comment.