mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
[AC-3043] Refactor AuthService to only use organization api key login (#622)
* Remove jslib authService and unused loginStrategies * Delete KeyConnectorService * Move OrganizationLoginStrategy into base LoginStrategy * Remove unused code and services from loginStrategy * Delete OrganizationService * Move loginStrategy into authService
This commit is contained in:
4
src/abstractions/auth.service.ts
Normal file
4
src/abstractions/auth.service.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export abstract class AuthService {
|
||||
logIn: (credentials: { clientId: string; clientSecret: string }) => Promise<void>;
|
||||
logOut: (callback: () => void) => void;
|
||||
}
|
||||
@@ -3,13 +3,12 @@ import { Router } from "@angular/router";
|
||||
import { takeUntil } from "rxjs";
|
||||
|
||||
import { ModalService } from "@/jslib/angular/src/services/modal.service";
|
||||
import { AuthService } from "@/jslib/common/src/abstractions/auth.service";
|
||||
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
import { ApiLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
|
||||
import { AuthService } from "../../abstractions/auth.service";
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
|
||||
import { EnvironmentComponent } from "./environment.component";
|
||||
@@ -81,9 +80,10 @@ export class ApiKeyComponent {
|
||||
}
|
||||
|
||||
try {
|
||||
this.formPromise = this.authService.logIn(
|
||||
new ApiLogInCredentials(this.clientId, this.clientSecret),
|
||||
);
|
||||
this.formPromise = this.authService.logIn({
|
||||
clientId: this.clientId,
|
||||
clientSecret: this.clientSecret,
|
||||
});
|
||||
await this.formPromise;
|
||||
const organizationId = await this.stateService.getEntityId();
|
||||
await this.stateService.setOrganizationId(organizationId);
|
||||
|
||||
@@ -10,7 +10,6 @@ import { DomSanitizer } from "@angular/platform-browser";
|
||||
import { Router } from "@angular/router";
|
||||
import { IndividualConfig, ToastrService } from "ngx-toastr";
|
||||
|
||||
import { AuthService } from "@/jslib/common/src/abstractions/auth.service";
|
||||
import { BroadcasterService } from "@/jslib/common/src/abstractions/broadcaster.service";
|
||||
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||
@@ -18,6 +17,7 @@ import { MessagingService } from "@/jslib/common/src/abstractions/messaging.serv
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
||||
|
||||
import { AuthService } from "../abstractions/auth.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
import { SyncService } from "../services/sync.service";
|
||||
|
||||
|
||||
@@ -3,20 +3,17 @@ import { APP_INITIALIZER, NgModule } from "@angular/core";
|
||||
import { JslibServicesModule } from "@/jslib/angular/src/services/jslib-services.module";
|
||||
import { ApiService as ApiServiceAbstraction } from "@/jslib/common/src/abstractions/api.service";
|
||||
import { AppIdService as AppIdServiceAbstraction } from "@/jslib/common/src/abstractions/appId.service";
|
||||
import { AuthService as AuthServiceAbstraction } from "@/jslib/common/src/abstractions/auth.service";
|
||||
import { BroadcasterService as BroadcasterServiceAbstraction } from "@/jslib/common/src/abstractions/broadcaster.service";
|
||||
import { CryptoService as CryptoServiceAbstraction } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@/jslib/common/src/abstractions/cryptoFunction.service";
|
||||
import { EnvironmentService as EnvironmentServiceAbstraction } from "@/jslib/common/src/abstractions/environment.service";
|
||||
import { I18nService as I18nServiceAbstraction } from "@/jslib/common/src/abstractions/i18n.service";
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@/jslib/common/src/abstractions/keyConnector.service";
|
||||
import { LogService as LogServiceAbstraction } from "@/jslib/common/src/abstractions/log.service";
|
||||
import { MessagingService as MessagingServiceAbstraction } from "@/jslib/common/src/abstractions/messaging.service";
|
||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { StateMigrationService as StateMigrationServiceAbstraction } from "@/jslib/common/src/abstractions/stateMigration.service";
|
||||
import { StorageService as StorageServiceAbstraction } from "@/jslib/common/src/abstractions/storage.service";
|
||||
import { TokenService as TokenServiceAbstraction } from "@/jslib/common/src/abstractions/token.service";
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { StateFactory } from "@/jslib/common/src/factories/stateFactory";
|
||||
import { GlobalState } from "@/jslib/common/src/models/domain/globalState";
|
||||
import { ContainerService } from "@/jslib/common/src/services/container.service";
|
||||
@@ -28,11 +25,11 @@ import { ElectronRendererStorageService } from "@/jslib/electron/src/services/el
|
||||
import { NodeApiService } from "@/jslib/node/src/services/nodeApi.service";
|
||||
import { NodeCryptoFunctionService } from "@/jslib/node/src/services/nodeCryptoFunction.service";
|
||||
|
||||
import { AuthService as AuthServiceAbstraction } from "../../abstractions/auth.service";
|
||||
import { StateService as StateServiceAbstraction } from "../../abstractions/state.service";
|
||||
import { Account } from "../../models/account";
|
||||
import { AuthService } from "../../services/auth.service";
|
||||
import { I18nService } from "../../services/i18n.service";
|
||||
import { NoopTwoFactorService } from "../../services/noop/noopTwoFactor.service";
|
||||
import { StateService } from "../../services/state.service";
|
||||
import { StateMigrationService } from "../../services/stateMigration.service";
|
||||
import { SyncService } from "../../services/sync.service";
|
||||
@@ -160,18 +157,11 @@ export function initFactory(
|
||||
provide: AuthServiceAbstraction,
|
||||
useClass: AuthService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
TokenServiceAbstraction,
|
||||
AppIdServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
LogServiceAbstraction,
|
||||
KeyConnectorServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
TwoFactorServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@@ -225,11 +215,6 @@ export function initFactory(
|
||||
StateMigrationServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: TwoFactorServiceAbstraction,
|
||||
useClass: NoopTwoFactorService,
|
||||
deps: [],
|
||||
}),
|
||||
] satisfies SafeProvider[],
|
||||
})
|
||||
export class ServicesModule {}
|
||||
|
||||
28
src/bwdc.ts
28
src/bwdc.ts
@@ -2,7 +2,6 @@ import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import { StorageService as StorageServiceAbstraction } from "@/jslib/common/src/abstractions/storage.service";
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { ClientType } from "@/jslib/common/src/enums/clientType";
|
||||
import { LogLevelType } from "@/jslib/common/src/enums/logLevelType";
|
||||
import { StateFactory } from "@/jslib/common/src/factories/stateFactory";
|
||||
@@ -11,9 +10,7 @@ import { AppIdService } from "@/jslib/common/src/services/appId.service";
|
||||
import { ContainerService } from "@/jslib/common/src/services/container.service";
|
||||
import { CryptoService } from "@/jslib/common/src/services/crypto.service";
|
||||
import { EnvironmentService } from "@/jslib/common/src/services/environment.service";
|
||||
import { KeyConnectorService } from "@/jslib/common/src/services/keyConnector.service";
|
||||
import { NoopMessagingService } from "@/jslib/common/src/services/noopMessaging.service";
|
||||
import { OrganizationService } from "@/jslib/common/src/services/organization.service";
|
||||
import { TokenService } from "@/jslib/common/src/services/token.service";
|
||||
import { CliPlatformUtilsService } from "@/jslib/node/src/cli/services/cliPlatformUtils.service";
|
||||
import { ConsoleLogService } from "@/jslib/node/src/cli/services/consoleLog.service";
|
||||
@@ -26,7 +23,6 @@ import { AuthService } from "./services/auth.service";
|
||||
import { I18nService } from "./services/i18n.service";
|
||||
import { KeytarSecureStorageService } from "./services/keytarSecureStorage.service";
|
||||
import { LowdbStorageService } from "./services/lowdbStorage.service";
|
||||
import { NoopTwoFactorService } from "./services/noop/noopTwoFactor.service";
|
||||
import { StateService } from "./services/state.service";
|
||||
import { StateMigrationService } from "./services/stateMigration.service";
|
||||
import { SyncService } from "./services/sync.service";
|
||||
@@ -53,11 +49,8 @@ export class Main {
|
||||
cryptoFunctionService: NodeCryptoFunctionService;
|
||||
authService: AuthService;
|
||||
syncService: SyncService;
|
||||
keyConnectorService: KeyConnectorService;
|
||||
stateService: StateService;
|
||||
stateMigrationService: StateMigrationService;
|
||||
organizationService: OrganizationService;
|
||||
twoFactorService: TwoFactorServiceAbstraction;
|
||||
|
||||
constructor() {
|
||||
const applicationName = "Bitwarden Directory Connector";
|
||||
@@ -145,33 +138,12 @@ export class Main {
|
||||
);
|
||||
this.containerService = new ContainerService(this.cryptoService);
|
||||
|
||||
this.organizationService = new OrganizationService(this.stateService);
|
||||
|
||||
this.keyConnectorService = new KeyConnectorService(
|
||||
this.stateService,
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
this.tokenService,
|
||||
this.logService,
|
||||
this.organizationService,
|
||||
this.cryptoFunctionService,
|
||||
);
|
||||
|
||||
this.twoFactorService = new NoopTwoFactorService();
|
||||
|
||||
this.authService = new AuthService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
this.tokenService,
|
||||
this.appIdService,
|
||||
this.platformUtilsService,
|
||||
this.messagingService,
|
||||
this.logService,
|
||||
this.keyConnectorService,
|
||||
this.environmentService,
|
||||
this.stateService,
|
||||
this.twoFactorService,
|
||||
this.i18nService,
|
||||
);
|
||||
|
||||
this.syncService = new SyncService(
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { AuthService } from "@/jslib/common/src/abstractions/auth.service";
|
||||
import { AuthResult } from "@/jslib/common/src/models/domain/authResult";
|
||||
import { ApiLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
import { AuthService } from "../abstractions/auth.service";
|
||||
|
||||
import { LoginCommand } from "./login.command";
|
||||
|
||||
@@ -37,11 +35,9 @@ describe("LoginCommand", () => {
|
||||
process.env.BW_CLIENTID = clientId;
|
||||
process.env.BW_CLIENTSECRET = clientSecret;
|
||||
|
||||
authService.logIn.mockResolvedValue(new AuthResult()); // logging in with api key does not set any flag on the authResult
|
||||
|
||||
const result = await loginCommand.run();
|
||||
|
||||
expect(authService.logIn).toHaveBeenCalledWith(new ApiLogInCredentials(clientId, clientSecret));
|
||||
expect(authService.logIn).toHaveBeenCalledWith({ clientId, clientSecret });
|
||||
expect(result).toMatchObject({
|
||||
data: {
|
||||
title: "You are logged in!",
|
||||
@@ -51,11 +47,9 @@ describe("LoginCommand", () => {
|
||||
});
|
||||
|
||||
it("uses client id and secret prompted from the user", async () => {
|
||||
authService.logIn.mockResolvedValue(new AuthResult()); // logging in with api key does not set any flag on the authResult
|
||||
|
||||
const result = await loginCommand.run();
|
||||
|
||||
expect(authService.logIn).toHaveBeenCalledWith(new ApiLogInCredentials(clientId, clientSecret));
|
||||
expect(authService.logIn).toHaveBeenCalledWith({ clientId, clientSecret });
|
||||
expect(result).toMatchObject({
|
||||
data: {
|
||||
title: "You are logged in!",
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import * as inquirer from "inquirer";
|
||||
|
||||
import { AuthService } from "@/jslib/common/src/abstractions/auth.service";
|
||||
import { ApiLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
import { Response } from "@/jslib/node/src/cli/models/response";
|
||||
import { MessageResponse } from "@/jslib/node/src/cli/models/response/messageResponse";
|
||||
|
||||
import { Utils } from "../../jslib/common/src/misc/utils";
|
||||
import { AuthService } from "../abstractions/auth.service";
|
||||
|
||||
export class LoginCommand {
|
||||
private canInteract: boolean;
|
||||
@@ -26,7 +25,7 @@ export class LoginCommand {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.authService.logIn(new ApiLogInCredentials(clientId, clientSecret));
|
||||
await this.authService.logIn({ clientId, clientSecret });
|
||||
|
||||
const res = new MessageResponse("You are logged in!", null);
|
||||
return Response.success(res);
|
||||
|
||||
21
src/commands/logout.command.ts
Normal file
21
src/commands/logout.command.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
import { Response } from "@/jslib/node/src/cli/models/response";
|
||||
import { MessageResponse } from "@/jslib/node/src/cli/models/response/messageResponse";
|
||||
|
||||
import { AuthService } from "../abstractions/auth.service";
|
||||
|
||||
export class LogoutCommand {
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private logoutCallback: () => Promise<void>,
|
||||
) {}
|
||||
|
||||
async run() {
|
||||
await this.logoutCallback();
|
||||
this.authService.logOut(() => {
|
||||
/* Do nothing */
|
||||
});
|
||||
const res = new MessageResponse("You have logged out.", null);
|
||||
return Response.success(res);
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import { LogInStrategy } from "@/jslib/common/src/misc/logInStrategies/logIn.strategy";
|
||||
import {
|
||||
AccountKeys,
|
||||
AccountProfile,
|
||||
AccountTokens,
|
||||
} from "@/jslib/common/src/models/domain/account";
|
||||
import { AuthResult } from "@/jslib/common/src/models/domain/authResult";
|
||||
import { ApiLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
import { ApiTokenRequest } from "@/jslib/common/src/models/request/identityToken/apiTokenRequest";
|
||||
import { IdentityTokenResponse } from "@/jslib/common/src/models/response/identityTokenResponse";
|
||||
|
||||
import { Account, DirectoryConfigurations, DirectorySettings } from "@/src/models/account";
|
||||
|
||||
export class OrganizationLogInStrategy extends LogInStrategy {
|
||||
tokenRequest: ApiTokenRequest;
|
||||
|
||||
async logIn(credentials: ApiLogInCredentials) {
|
||||
this.tokenRequest = new ApiTokenRequest(
|
||||
credentials.clientId,
|
||||
credentials.clientSecret,
|
||||
await this.buildTwoFactor(),
|
||||
await this.buildDeviceRequest(),
|
||||
);
|
||||
|
||||
return this.startLogIn();
|
||||
}
|
||||
|
||||
protected async processTokenResponse(response: IdentityTokenResponse): Promise<AuthResult> {
|
||||
await this.saveAccountInformation(response);
|
||||
return new AuthResult();
|
||||
}
|
||||
|
||||
protected async saveAccountInformation(tokenResponse: IdentityTokenResponse) {
|
||||
const clientId = this.tokenRequest.clientId;
|
||||
const entityId = clientId.split("organization.")[1];
|
||||
const clientSecret = this.tokenRequest.clientSecret;
|
||||
|
||||
await this.stateService.addAccount(
|
||||
new Account({
|
||||
profile: {
|
||||
...new AccountProfile(),
|
||||
...{
|
||||
userId: entityId,
|
||||
apiKeyClientId: clientId,
|
||||
entityId: entityId,
|
||||
},
|
||||
},
|
||||
tokens: {
|
||||
...new AccountTokens(),
|
||||
...{
|
||||
accessToken: tokenResponse.accessToken,
|
||||
refreshToken: tokenResponse.refreshToken,
|
||||
},
|
||||
},
|
||||
keys: {
|
||||
...new AccountKeys(),
|
||||
...{
|
||||
apiKeyClientSecret: clientSecret,
|
||||
},
|
||||
},
|
||||
directorySettings: new DirectorySettings(),
|
||||
directoryConfigurations: new DirectoryConfigurations(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { Command, OptionValues } from "commander";
|
||||
|
||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
import { BaseProgram } from "@/jslib/node/src/cli/baseProgram";
|
||||
import { LogoutCommand } from "@/jslib/node/src/cli/commands/logout.command";
|
||||
import { UpdateCommand } from "@/jslib/node/src/cli/commands/update.command";
|
||||
import { Response } from "@/jslib/node/src/cli/models/response";
|
||||
import { StringResponse } from "@/jslib/node/src/cli/models/response/stringResponse";
|
||||
@@ -15,6 +14,7 @@ import { ClearCacheCommand } from "./commands/clearCache.command";
|
||||
import { ConfigCommand } from "./commands/config.command";
|
||||
import { LastSyncCommand } from "./commands/lastSync.command";
|
||||
import { LoginCommand } from "./commands/login.command";
|
||||
import { LogoutCommand } from "./commands/logout.command";
|
||||
import { SyncCommand } from "./commands/sync.command";
|
||||
import { TestCommand } from "./commands/test.command";
|
||||
|
||||
@@ -118,7 +118,6 @@ export class Program extends BaseProgram {
|
||||
await this.exitIfNotAuthed();
|
||||
const command = new LogoutCommand(
|
||||
this.main.authService,
|
||||
this.main.i18nService,
|
||||
async () => await this.main.logout(),
|
||||
);
|
||||
const response = await command.run();
|
||||
|
||||
@@ -1,65 +1,91 @@
|
||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { EnvironmentService } from "@/jslib/common/src/abstractions/environment.service";
|
||||
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
||||
import { KeyConnectorService } from "@/jslib/common/src/abstractions/keyConnector.service";
|
||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { AuthResult } from "@/jslib/common/src/models/domain/authResult";
|
||||
import { ApiLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
import { AuthService as AuthServiceBase } from "@/jslib/common/src/services/auth.service";
|
||||
import {
|
||||
AccountKeys,
|
||||
AccountProfile,
|
||||
AccountTokens,
|
||||
} from "@/jslib/common/src/models/domain/account";
|
||||
import { DeviceRequest } from "@/jslib/common/src/models/request/deviceRequest";
|
||||
import { ApiTokenRequest } from "@/jslib/common/src/models/request/identityToken/apiTokenRequest";
|
||||
import { TokenRequestTwoFactor } from "@/jslib/common/src/models/request/identityToken/tokenRequestTwoFactor";
|
||||
import { IdentityTokenResponse } from "@/jslib/common/src/models/response/identityTokenResponse";
|
||||
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
import { OrganizationLogInStrategy } from "../misc/logInStrategies/organizationLogIn.strategy";
|
||||
import { Account, DirectoryConfigurations, DirectorySettings } from "../models/account";
|
||||
|
||||
export class AuthService extends AuthServiceBase {
|
||||
export class AuthService {
|
||||
constructor(
|
||||
cryptoService: CryptoService,
|
||||
apiService: ApiService,
|
||||
tokenService: TokenService,
|
||||
appIdService: AppIdService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
messagingService: MessagingService,
|
||||
logService: LogService,
|
||||
keyConnectorService: KeyConnectorService,
|
||||
environmentService: EnvironmentService,
|
||||
stateService: StateService,
|
||||
twoFactorService: TwoFactorService,
|
||||
i18nService: I18nService,
|
||||
) {
|
||||
super(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
logService,
|
||||
keyConnectorService,
|
||||
environmentService,
|
||||
stateService,
|
||||
twoFactorService,
|
||||
i18nService,
|
||||
private apiService: ApiService,
|
||||
private appIdService: AppIdService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private messagingService: MessagingService,
|
||||
private stateService: StateService,
|
||||
) {}
|
||||
|
||||
async logIn(credentials: { clientId: string; clientSecret: string }) {
|
||||
const tokenRequest = new ApiTokenRequest(
|
||||
credentials.clientId,
|
||||
credentials.clientSecret,
|
||||
new TokenRequestTwoFactor(), // unused
|
||||
await this.buildDeviceRequest(),
|
||||
);
|
||||
|
||||
const response = await this.apiService.postIdentityToken(tokenRequest);
|
||||
|
||||
if (response instanceof IdentityTokenResponse) {
|
||||
await this.saveAccountInformation(tokenRequest, response);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error("Invalid response object.");
|
||||
}
|
||||
|
||||
async logIn(credentials: ApiLogInCredentials): Promise<AuthResult> {
|
||||
const strategy = new OrganizationLogInStrategy(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
this.tokenService,
|
||||
this.appIdService,
|
||||
this.platformUtilsService,
|
||||
this.messagingService,
|
||||
this.logService,
|
||||
this.stateService,
|
||||
this.twoFactorService,
|
||||
);
|
||||
logOut(callback: () => void) {
|
||||
callback();
|
||||
this.messagingService.send("loggedOut");
|
||||
}
|
||||
|
||||
return strategy.logIn(credentials);
|
||||
private async buildDeviceRequest() {
|
||||
const appId = await this.appIdService.getAppId();
|
||||
return new DeviceRequest(appId, this.platformUtilsService);
|
||||
}
|
||||
|
||||
private async saveAccountInformation(
|
||||
tokenRequest: ApiTokenRequest,
|
||||
tokenResponse: IdentityTokenResponse,
|
||||
) {
|
||||
const clientId = tokenRequest.clientId;
|
||||
const entityId = clientId.split("organization.")[1];
|
||||
const clientSecret = tokenRequest.clientSecret;
|
||||
|
||||
await this.stateService.addAccount(
|
||||
new Account({
|
||||
profile: {
|
||||
...new AccountProfile(),
|
||||
...{
|
||||
userId: entityId,
|
||||
apiKeyClientId: clientId,
|
||||
entityId: entityId,
|
||||
},
|
||||
},
|
||||
tokens: {
|
||||
...new AccountTokens(),
|
||||
...{
|
||||
accessToken: tokenResponse.accessToken,
|
||||
refreshToken: tokenResponse.refreshToken,
|
||||
},
|
||||
},
|
||||
keys: {
|
||||
...new AccountKeys(),
|
||||
...{
|
||||
apiKeyClientSecret: clientSecret,
|
||||
},
|
||||
},
|
||||
directorySettings: new DirectorySettings(),
|
||||
directoryConfigurations: new DirectoryConfigurations(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
97
src/services/authService.spec.ts
Normal file
97
src/services/authService.spec.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
import {
|
||||
AccountKeys,
|
||||
AccountProfile,
|
||||
AccountTokens,
|
||||
} from "@/jslib/common/src/models/domain/account";
|
||||
import { IdentityTokenResponse } from "@/jslib/common/src/models/response/identityTokenResponse";
|
||||
|
||||
import { MessagingService } from "../../jslib/common/src/abstractions/messaging.service";
|
||||
import { Account, DirectoryConfigurations, DirectorySettings } from "../models/account";
|
||||
|
||||
import { AuthService } from "./auth.service";
|
||||
import { StateService } from "./state.service";
|
||||
|
||||
const clientId = "organization.CLIENT_ID";
|
||||
const clientSecret = "CLIENT_SECRET";
|
||||
|
||||
const deviceId = Utils.newGuid();
|
||||
const accessToken = "ACCESS_TOKEN";
|
||||
const refreshToken = "REFRESH_TOKEN";
|
||||
|
||||
export function identityTokenResponseFactory() {
|
||||
return new IdentityTokenResponse({
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken, // not actually sure this is sent but including it out of caution
|
||||
expires_in: 3600,
|
||||
token_type: "Bearer",
|
||||
scope: "api.organization",
|
||||
});
|
||||
}
|
||||
|
||||
describe("AuthService", () => {
|
||||
let apiService: SubstituteOf<ApiService>;
|
||||
let appIdService: SubstituteOf<AppIdService>;
|
||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
||||
let messagingService: SubstituteOf<MessagingService>;
|
||||
let stateService: SubstituteOf<StateService>;
|
||||
|
||||
let authService: AuthService;
|
||||
|
||||
beforeEach(async () => {
|
||||
apiService = Substitute.for();
|
||||
appIdService = Substitute.for();
|
||||
platformUtilsService = Substitute.for();
|
||||
stateService = Substitute.for();
|
||||
messagingService = Substitute.for();
|
||||
|
||||
appIdService.getAppId().resolves(deviceId);
|
||||
|
||||
authService = new AuthService(
|
||||
apiService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
stateService,
|
||||
);
|
||||
});
|
||||
|
||||
it("sets the local environment after a successful login", async () => {
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
|
||||
await authService.logIn({ clientId, clientSecret });
|
||||
|
||||
stateService.received(1).addAccount(
|
||||
new Account({
|
||||
profile: {
|
||||
...new AccountProfile(),
|
||||
...{
|
||||
userId: "CLIENT_ID",
|
||||
apiKeyClientId: clientId, // with the "organization." prefix
|
||||
entityId: "CLIENT_ID",
|
||||
},
|
||||
},
|
||||
tokens: {
|
||||
...new AccountTokens(),
|
||||
...{
|
||||
accessToken: accessToken,
|
||||
refreshToken: refreshToken,
|
||||
},
|
||||
},
|
||||
keys: {
|
||||
...new AccountKeys(),
|
||||
...{
|
||||
apiKeyClientSecret: clientSecret,
|
||||
},
|
||||
},
|
||||
directorySettings: new DirectorySettings(),
|
||||
directoryConfigurations: new DirectoryConfigurations(),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,40 +0,0 @@
|
||||
import {
|
||||
TwoFactorProviderDetails,
|
||||
TwoFactorService,
|
||||
} from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { TwoFactorProviderType } from "@/jslib/common/src/enums/twoFactorProviderType";
|
||||
import { IdentityTwoFactorResponse } from "@/jslib/common/src/models/response/identityTwoFactorResponse";
|
||||
|
||||
export class NoopTwoFactorService implements TwoFactorService {
|
||||
init() {
|
||||
// Noop
|
||||
}
|
||||
|
||||
getSupportedProviders(win: Window): TwoFactorProviderDetails[] {
|
||||
return null;
|
||||
}
|
||||
|
||||
getDefaultProvider(webAuthnSupported: boolean): TwoFactorProviderType {
|
||||
return null;
|
||||
}
|
||||
|
||||
setSelectedProvider(type: TwoFactorProviderType) {
|
||||
// Noop
|
||||
}
|
||||
|
||||
clearSelectedProvider() {
|
||||
// Noop
|
||||
}
|
||||
|
||||
setProviders(response: IdentityTwoFactorResponse) {
|
||||
// Noop
|
||||
}
|
||||
|
||||
clearProviders() {
|
||||
// Noop
|
||||
}
|
||||
|
||||
getProviders(): Map<TwoFactorProviderType, { [key: string]: string }> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user