Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added the 'accesstoken get' command solving #1072
- Loading branch information
1 parent
062093d
commit 005dcc7
Showing
7 changed files
with
311 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# accesstoken get | ||
|
||
Gets access token for the specified resource | ||
|
||
## Usage | ||
|
||
```sh | ||
accesstoken get [options] | ||
``` | ||
|
||
## Options | ||
|
||
Option|Description | ||
------|----------- | ||
`--help`|output usage information | ||
`-r, --resource <resource>`|The resource for which to retrieve an access token | ||
`--new`|Retrieve a new access token to ensure that it's valid for as long as possible | ||
`-o, --output [output]`|Output type. `json|text`. Default `text` | ||
`--verbose`|Runs command with verbose logging | ||
`--debug`|Runs command with debug logging | ||
|
||
## Remarks | ||
|
||
The `accesstoken get` command returns an access token for the specified resource. If an access token has been previously retrieved and is still valid, the command will return the cached token. If you want to ensure that the returned access token is valid for as long as possible, you can force the command to retrieve a new access token by using the `--new` option. | ||
|
||
## Examples | ||
|
||
Get access token for the Microsoft Graph | ||
|
||
```sh | ||
accesstoken get --resource https://graph.microsoft.com | ||
``` | ||
|
||
Get a new access token for SharePoint Online | ||
|
||
```sh | ||
accesstoken get --resource https://contoso.sharepoint.com --new | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import commands from './commands'; | ||
import Command, { CommandOption, CommandValidate, CommandError } from '../../Command'; | ||
import * as sinon from 'sinon'; | ||
const command: Command = require('./accesstoken-get'); | ||
import * as assert from 'assert'; | ||
import Utils from '../../Utils'; | ||
import appInsights from '../../appInsights'; | ||
import auth from '../../Auth'; | ||
|
||
describe(commands.ACCESSTOKEN_GET, () => { | ||
let vorpal: Vorpal; | ||
let log: any[]; | ||
let cmdInstanceLogSpy: sinon.SinonSpy; | ||
let cmdInstance: any; | ||
|
||
before(() => { | ||
sinon.stub(appInsights, 'trackEvent').callsFake(() => { }); | ||
sinon.stub(auth, 'restoreAuth').callsFake(() => Promise.resolve()); | ||
auth.service.connected = true; | ||
}); | ||
|
||
beforeEach(() => { | ||
vorpal = require('../../vorpal-init'); | ||
log = []; | ||
cmdInstance = { | ||
commandWrapper: { | ||
command: command.name | ||
}, | ||
action: command.action(), | ||
log: (msg: any) => { | ||
log.push(msg); | ||
} | ||
}; | ||
cmdInstanceLogSpy = sinon.spy(cmdInstance, 'log'); | ||
}); | ||
|
||
afterEach(() => { | ||
Utils.restore([ | ||
vorpal.find, | ||
auth.ensureAccessToken | ||
]); | ||
auth.service.accessTokens = {}; | ||
}); | ||
|
||
after(() => { | ||
Utils.restore([ | ||
appInsights.trackEvent, | ||
auth.restoreAuth | ||
]); | ||
}); | ||
|
||
it('has correct name', () => { | ||
assert.equal(command.name.startsWith(commands.ACCESSTOKEN_GET), true); | ||
}); | ||
|
||
it('has a description', () => { | ||
assert.notEqual(command.description, null); | ||
}); | ||
|
||
it('retrieves access token for the specified resource', (done) => { | ||
const d: Date = new Date(); | ||
d.setMinutes(d.getMinutes() + 1); | ||
auth.service.accessTokens['https://graph.microsoft.com'] = { | ||
expiresOn: d.toString(), | ||
value: 'ABC' | ||
}; | ||
|
||
cmdInstance.action({ options: { debug: false, resource: 'https://graph.microsoft.com' } }, () => { | ||
try { | ||
assert(cmdInstanceLogSpy.calledWith('ABC')); | ||
done(); | ||
} | ||
catch (e) { | ||
done(e); | ||
} | ||
}); | ||
}); | ||
|
||
it('correctly handles error when retrieving access token', (done) => { | ||
sinon.stub(auth, 'ensureAccessToken').callsFake(() => Promise.reject('An error has occurred')); | ||
|
||
cmdInstance.action({ options: { debug: false, resource: 'https://graph.microsoft.com' } }, (err?: any) => { | ||
try { | ||
assert.equal(JSON.stringify(err), JSON.stringify(new CommandError('An error has occurred'))); | ||
done(); | ||
} | ||
catch (e) { | ||
done(e); | ||
} | ||
}); | ||
}); | ||
|
||
it('fails validation if resource is not passed', () => { | ||
const actual = (command.validate() as CommandValidate)({ options: {} }); | ||
assert.notEqual(actual, true); | ||
}); | ||
|
||
it('fails validation if resource is undefined', () => { | ||
const actual = (command.validate() as CommandValidate)({ options: { resource: undefined } }); | ||
assert.notEqual(actual, true); | ||
}); | ||
|
||
it('fails validation if resource is blank', () => { | ||
const actual = (command.validate() as CommandValidate)({ options: { resource: '' } }); | ||
assert.notEqual(actual, true); | ||
}); | ||
|
||
it('passes validation when resource is specified', () => { | ||
const actual = (command.validate() as CommandValidate)({ options: { resource: 'https://graph.microsoft.com' } }); | ||
assert.equal(actual, true); | ||
}); | ||
|
||
it('supports debug mode', () => { | ||
const options = (command.options() as CommandOption[]); | ||
let containsOption = false; | ||
options.forEach(o => { | ||
if (o.option === '--debug') { | ||
containsOption = true; | ||
} | ||
}); | ||
assert(containsOption); | ||
}); | ||
|
||
it('has help referring to the right command', () => { | ||
const cmd: any = { | ||
log: (msg: string) => { }, | ||
prompt: () => { }, | ||
helpInformation: () => { } | ||
}; | ||
const find = sinon.stub(vorpal, 'find').callsFake(() => cmd); | ||
cmd.help = command.help(); | ||
cmd.help({}, () => { }); | ||
assert(find.calledWith(commands.ACCESSTOKEN_GET)); | ||
}); | ||
|
||
it('has help with examples', () => { | ||
const _log: string[] = []; | ||
const cmd: any = { | ||
log: (msg: string) => { | ||
_log.push(msg); | ||
}, | ||
prompt: () => { }, | ||
helpInformation: () => { } | ||
}; | ||
sinon.stub(vorpal, 'find').callsFake(() => cmd); | ||
cmd.help = command.help(); | ||
cmd.help({}, () => { }); | ||
let containsExamples: boolean = false; | ||
_log.forEach(l => { | ||
if (l && l.indexOf('Examples:') > -1) { | ||
containsExamples = true; | ||
} | ||
}); | ||
Utils.restore(vorpal.find); | ||
assert(containsExamples); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import commands from './commands'; | ||
import GlobalOptions from '../../GlobalOptions'; | ||
import Command, { | ||
CommandOption, | ||
CommandValidate, | ||
CommandError | ||
} from '../../Command'; | ||
import auth from '../../Auth'; | ||
|
||
const vorpal: Vorpal = require('../../vorpal-init'); | ||
|
||
interface CommandArgs { | ||
options: Options; | ||
} | ||
|
||
interface Options extends GlobalOptions { | ||
new?: boolean; | ||
resource: string; | ||
} | ||
|
||
class AccessTokenGetCommand extends Command { | ||
public get name(): string { | ||
return `${commands.ACCESSTOKEN_GET}`; | ||
} | ||
|
||
public get description(): string { | ||
return 'Gets access token for the specified resource'; | ||
} | ||
|
||
public commandAction(cmd: CommandInstance, args: CommandArgs, cb: (err?: any) => void): void { | ||
auth | ||
.ensureAccessToken(args.options.resource, cmd, this.debug, args.options.new) | ||
.then((accessToken: string): void => { | ||
cmd.log(accessToken); | ||
cb(); | ||
}, (err: any): void => cb(new CommandError(err))); | ||
} | ||
|
||
public options(): CommandOption[] { | ||
const options: CommandOption[] = [ | ||
{ | ||
option: '-r, --resource <resource>', | ||
description: 'The resource for which to retrieve an access token' | ||
}, | ||
{ | ||
option: '--new', | ||
description: 'Retrieve a new access token to ensure that it\'s valid for as long as possible' | ||
} | ||
]; | ||
|
||
const parentOptions: CommandOption[] = super.options(); | ||
return options.concat(parentOptions); | ||
} | ||
|
||
public validate(): CommandValidate { | ||
return (args: CommandArgs): boolean | string => { | ||
if (!args.options.resource) { | ||
return 'Required parameter resource missing'; | ||
} | ||
|
||
return true; | ||
}; | ||
} | ||
|
||
public commandHelp(args: any, log: (help: string) => void): void { | ||
const chalk = vorpal.chalk; | ||
log(vorpal.find(this.name).helpInformation()); | ||
log( | ||
`Remarks: | ||
The ${chalk.blue(this.name)} command returns an access token for the specified | ||
resource. If an access token has been previously retrieved and is still | ||
valid, the command will return the cached token. If you want to ensure that | ||
the returned access token is valid for as long as possible, you can force | ||
the command to retrieve a new access token by using the ${chalk.grey('--new')} option. | ||
Examples: | ||
Get access token for the Microsoft Graph | ||
${this.name} --resource https://graph.microsoft.com | ||
Get a new access token for SharePoint Online | ||
${this.name} --resource https://contoso.sharepoint.com --new | ||
`); | ||
} | ||
} | ||
|
||
module.exports = new AccessTokenGetCommand(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters