mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-18 09:13:28 +00:00
Use organization api key for auth (#121)
* Use api key for login * Remove user login and organization setting * Override Api authentication to expect organization keys * Linter fixes * Use public API The organization api key is valid only in the public api scope * Use organization api key in CLI utility * Serialize storageService writes * Prefer multiple awaits to .then chains * Initial PR review * Do not treat api key inputs as passwords This conforms with how they are handled in CLI/web * Update jslib * PR feedback
This commit is contained in:
@@ -16,9 +16,12 @@ import { UpdateCommand } from 'jslib/cli/commands/update.command';
|
||||
|
||||
import { BaseProgram } from 'jslib/cli/baseProgram';
|
||||
|
||||
import { ApiKeyService } from 'jslib/abstractions/apiKey.service';
|
||||
import { Response } from 'jslib/cli/models/response';
|
||||
import { StringResponse } from 'jslib/cli/models/response/stringResponse';
|
||||
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
const writeLn = (s: string, finalLine: boolean = false, error: boolean = false) => {
|
||||
const stream = error ? process.stderr : process.stdout;
|
||||
if (finalLine && process.platform === 'win32') {
|
||||
@@ -29,8 +32,11 @@ const writeLn = (s: string, finalLine: boolean = false, error: boolean = false)
|
||||
};
|
||||
|
||||
export class Program extends BaseProgram {
|
||||
private apiKeyService: ApiKeyService;
|
||||
|
||||
constructor(private main: Main) {
|
||||
super(main.userService, writeLn);
|
||||
this.apiKeyService = main.apiKeyService;
|
||||
}
|
||||
|
||||
async run() {
|
||||
@@ -86,34 +92,26 @@ export class Program extends BaseProgram {
|
||||
});
|
||||
|
||||
program
|
||||
.command('login [email] [password]')
|
||||
.description('Log into a user account.')
|
||||
.option('--method <method>', 'Two-step login method.')
|
||||
.option('--code <code>', 'Two-step login code.')
|
||||
.option('--sso', 'Log in with Single-Sign On.')
|
||||
.option('--passwordenv <variable-name>', 'Read password from the named environment variable.')
|
||||
.option('--passwordfile <filename>', 'Read password from first line of the named file.')
|
||||
.on('--help', () => {
|
||||
writeLn('\n Notes:');
|
||||
writeLn('');
|
||||
writeLn(' See docs for valid `method` enum values.');
|
||||
writeLn('');
|
||||
writeLn(' Examples:');
|
||||
writeLn('');
|
||||
writeLn(' bwdc login');
|
||||
writeLn(' bwdc login john@example.com myPassword321');
|
||||
writeLn(' bwdc login john@example.com myPassword321 --method 1 --code 249213');
|
||||
writeLn(' bwdc login john@example.com --passwordfile passwd.txt --method 1 --code 249213');
|
||||
writeLn(' bwdc login john@example.com --passwordenv MY_PASSWD --method 1 --code 249213');
|
||||
writeLn(' bwdc login --sso');
|
||||
writeLn('', true);
|
||||
.command('login [clientId] [clientSecret]')
|
||||
.description('Log into an organization account.', {
|
||||
clientId: 'Client_id part of your organization\'s API key',
|
||||
clientSecret: 'Client_secret part of your organization\'s API key',
|
||||
})
|
||||
.action(async (email: string, password: string, options: program.OptionValues) => {
|
||||
.action(async (clientId: string, clientSecret: string, options: program.OptionValues) => {
|
||||
await this.exitIfAuthed();
|
||||
const command = new LoginCommand(this.main.authService, this.main.apiService, this.main.i18nService,
|
||||
this.main.environmentService, this.main.passwordGenerationService, this.main.cryptoFunctionService,
|
||||
this.main.platformUtilsService, 'connector');
|
||||
const response = await command.run(email, password, options);
|
||||
|
||||
if (!Utils.isNullOrWhitespace(clientId)) {
|
||||
process.env.BW_CLIENTID = clientId;
|
||||
}
|
||||
if (!Utils.isNullOrWhitespace(clientSecret)) {
|
||||
process.env.BW_CLIENTSECRET = clientSecret;
|
||||
}
|
||||
|
||||
options = Object.assign(options ?? {}, { apikey: true }); // force apikey use
|
||||
const response = await command.run(null, null, options);
|
||||
this.processResponse(response);
|
||||
});
|
||||
|
||||
@@ -284,4 +282,20 @@ export class Program extends BaseProgram {
|
||||
program.outputHelp();
|
||||
}
|
||||
}
|
||||
|
||||
async exitIfAuthed() {
|
||||
const authed = await this.apiKeyService.isAuthenticated();
|
||||
if (authed) {
|
||||
const type = await this.apiKeyService.getEntityType();
|
||||
const id = await this.apiKeyService.getEntityId();
|
||||
this.processResponse(Response.error('You are already logged in as ' + type + '.' + id + '.'), true);
|
||||
}
|
||||
}
|
||||
|
||||
async exitIfNotAuthed() {
|
||||
const authed = await this.apiKeyService.isAuthenticated();
|
||||
if (!authed) {
|
||||
this.processResponse(Response.error('You are not logged in.'), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user