mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
[Tech debt] Refactor authService (#213)
* Add OrganizationLogInStrategy * Use noop TwoFactorService
This commit is contained in:
2
jslib
2
jslib
Submodule jslib updated: e0cc754d6f...6b8508579f
@@ -12,8 +12,8 @@ import { StateService } from "../../abstractions/state.service";
|
||||
|
||||
import { ModalService } from "jslib-angular/services/modal.service";
|
||||
|
||||
import { HtmlStorageLocation } from "jslib-common/enums/htmlStorageLocation";
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
|
||||
|
||||
@Component({
|
||||
selector: "app-apiKey",
|
||||
@@ -76,7 +76,9 @@ export class ApiKeyComponent {
|
||||
}
|
||||
|
||||
try {
|
||||
this.formPromise = this.authService.logInApiKey(this.clientId, this.clientSecret);
|
||||
this.formPromise = this.authService.logIn(
|
||||
new ApiLogInCredentials(this.clientId, this.clientSecret)
|
||||
);
|
||||
await this.formPromise;
|
||||
const organizationId = await this.stateService.getEntityId();
|
||||
await this.stateService.setOrganizationId(organizationId);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { LaunchGuardService } from "./launch-guard.service";
|
||||
|
||||
import { I18nService } from "../../services/i18n.service";
|
||||
import { SyncService } from "../../services/sync.service";
|
||||
import { NoopTwoFactorService } from "../../services/noop/noopTwoFactor.service";
|
||||
|
||||
import { JslibServicesModule } from "jslib-angular/services/jslib-services.module";
|
||||
|
||||
@@ -34,11 +35,11 @@ import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-c
|
||||
import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service";
|
||||
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
|
||||
import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.service";
|
||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service";
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service";
|
||||
|
||||
import { StateService as StateServiceAbstraction } from "../../abstractions/state.service";
|
||||
|
||||
import { ApiService, refreshToken } from "../../services/api.service";
|
||||
import { refreshToken } from "../../services/api.service";
|
||||
import { AuthService } from "../../services/auth.service";
|
||||
import { StateService } from "../../services/state.service";
|
||||
import { StateMigrationService } from "../../services/stateMigration.service";
|
||||
@@ -60,7 +61,6 @@ function refreshTokenCallback(injector: Injector) {
|
||||
export function initFactory(
|
||||
environmentService: EnvironmentServiceAbstraction,
|
||||
i18nService: I18nService,
|
||||
authService: AuthService,
|
||||
platformUtilsService: PlatformUtilsServiceAbstraction,
|
||||
stateService: StateServiceAbstraction,
|
||||
cryptoService: CryptoServiceAbstraction
|
||||
@@ -69,7 +69,6 @@ export function initFactory(
|
||||
await stateService.init();
|
||||
await environmentService.setUrlsFromStorage();
|
||||
await i18nService.init();
|
||||
authService.init();
|
||||
const htmlEl = window.document.documentElement;
|
||||
htmlEl.classList.add("os_" + platformUtilsService.getDeviceString());
|
||||
htmlEl.classList.add("locale_" + i18nService.translationLocale);
|
||||
@@ -103,7 +102,6 @@ export function initFactory(
|
||||
deps: [
|
||||
EnvironmentServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
AuthServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
@@ -170,15 +168,13 @@ export function initFactory(
|
||||
ApiServiceAbstraction,
|
||||
TokenServiceAbstraction,
|
||||
AppIdServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
VaultTimeoutServiceAbstraction,
|
||||
LogServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
KeyConnectorServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
TwoFactorServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -232,6 +228,10 @@ export function initFactory(
|
||||
StateMigrationServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: TwoFactorServiceAbstraction,
|
||||
useClass: NoopTwoFactorService,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class ServicesModule {}
|
||||
|
||||
22
src/bwdc.ts
22
src/bwdc.ts
@@ -8,6 +8,7 @@ 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";
|
||||
@@ -37,15 +38,16 @@ import { SettingsService } from "jslib-common/services/settings.service";
|
||||
import { TokenService } from "jslib-common/services/token.service";
|
||||
|
||||
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service";
|
||||
|
||||
import { Program } from "./program";
|
||||
|
||||
import { Account } from "./models/account";
|
||||
|
||||
import { GlobalStateFactory } from "jslib-common/factories/globalStateFactory";
|
||||
import { StateFactory } from "jslib-common/factories/stateFactory";
|
||||
|
||||
import { GlobalState } from "jslib-common/models/domain/globalState";
|
||||
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
|
||||
|
||||
// tslint:disable-next-line
|
||||
const packageJson = require("./package.json");
|
||||
@@ -83,6 +85,7 @@ export class Main {
|
||||
stateMigrationService: StateMigrationService;
|
||||
organizationService: OrganizationService;
|
||||
providerService: ProviderService;
|
||||
twoFactorService: TwoFactorServiceAbstraction;
|
||||
|
||||
constructor() {
|
||||
const applicationName = "Bitwarden Directory Connector";
|
||||
@@ -160,7 +163,8 @@ export class Main {
|
||||
" (" +
|
||||
this.platformUtilsService.getDeviceString().toUpperCase() +
|
||||
")",
|
||||
(clientId, clientSecret) => this.authService.logInApiKey(clientId, clientSecret)
|
||||
(clientId, clientSecret) =>
|
||||
this.authService.logIn(new ApiLogInCredentials(clientId, clientSecret))
|
||||
);
|
||||
this.containerService = new ContainerService(this.cryptoService);
|
||||
|
||||
@@ -172,23 +176,24 @@ export class Main {
|
||||
this.apiService,
|
||||
this.tokenService,
|
||||
this.logService,
|
||||
this.organizationService
|
||||
this.organizationService,
|
||||
this.cryptoFunctionService
|
||||
);
|
||||
|
||||
this.twoFactorService = new NoopTwoFactorService();
|
||||
|
||||
this.authService = new AuthService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
this.tokenService,
|
||||
this.appIdService,
|
||||
this.i18nService,
|
||||
this.platformUtilsService,
|
||||
this.messagingService,
|
||||
null,
|
||||
this.logService,
|
||||
this.cryptoFunctionService,
|
||||
this.environmentService,
|
||||
this.keyConnectorService,
|
||||
this.stateService
|
||||
this.environmentService,
|
||||
this.stateService,
|
||||
this.twoFactorService
|
||||
);
|
||||
|
||||
this.syncService = new SyncService(
|
||||
@@ -281,7 +286,6 @@ export class Main {
|
||||
// });
|
||||
const locale = await this.stateService.getLocale();
|
||||
await this.i18nService.init(locale);
|
||||
this.authService.init();
|
||||
|
||||
const installedVersion = await this.stateService.getInstalledVersion();
|
||||
const currentVersion = await this.platformUtilsService.getApplicationVersion();
|
||||
|
||||
65
src/misc/logInStrategies/organizationLogIn.strategy.ts
Normal file
65
src/misc/logInStrategies/organizationLogIn.strategy.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { LogInStrategy } from "jslib-common/misc/logInStrategies/logIn.strategy";
|
||||
|
||||
import { ApiTokenRequest } from "jslib-common/models/request/identityToken/apiTokenRequest";
|
||||
|
||||
import { IdentityTokenResponse } from "jslib-common/models/response/identityTokenResponse";
|
||||
|
||||
import { AccountKeys, AccountProfile, AccountTokens } from "jslib-common/models/domain/account";
|
||||
import { AuthResult } from "jslib-common/models/domain/authResult";
|
||||
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
|
||||
|
||||
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(),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,7 @@ export class Program extends BaseProgram {
|
||||
this.main.stateService,
|
||||
this.main.cryptoService,
|
||||
this.main.policyService,
|
||||
this.main.twoFactorService,
|
||||
"connector"
|
||||
);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
|
||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
|
||||
import { ApiService as ApiServiceBase } from "jslib-common/services/api.service";
|
||||
|
||||
export async function refreshToken(stateService: StateService, authService: AuthService) {
|
||||
@@ -11,7 +12,7 @@ export async function refreshToken(stateService: StateService, authService: Auth
|
||||
const clientId = await stateService.getApiKeyClientId();
|
||||
const clientSecret = await stateService.getApiKeyClientSecret();
|
||||
if (clientId != null && clientSecret != null) {
|
||||
await authService.logInApiKey(clientId, clientSecret);
|
||||
await authService.logIn(new ApiLogInCredentials(clientId, clientSecret));
|
||||
}
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
import { OrganizationLogInStrategy } from "../misc/logInStrategies/organizationLogIn.strategy";
|
||||
|
||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||
import { AppIdService } from "jslib-common/abstractions/appId.service";
|
||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
|
||||
|
||||
import { AuthService as AuthServiceBase } from "jslib-common/services/auth.service";
|
||||
|
||||
import { Account, DirectoryConfigurations, DirectorySettings } from "src/models/account";
|
||||
|
||||
import { AccountKeys, AccountProfile, AccountTokens } from "jslib-common/models/domain/account";
|
||||
import { AuthResult } from "jslib-common/models/domain/authResult";
|
||||
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
|
||||
|
||||
import { DeviceRequest } from "jslib-common/models/request/deviceRequest";
|
||||
import { TokenRequest } from "jslib-common/models/request/tokenRequest";
|
||||
|
||||
import { IdentityTokenResponse } from "jslib-common/models/response/identityTokenResponse";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
export class AuthService extends AuthServiceBase {
|
||||
constructor(
|
||||
@@ -30,90 +24,42 @@ export class AuthService extends AuthServiceBase {
|
||||
apiService: ApiService,
|
||||
tokenService: TokenService,
|
||||
appIdService: AppIdService,
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
messagingService: MessagingService,
|
||||
vaultTimeoutService: VaultTimeoutService,
|
||||
logService: LogService,
|
||||
cryptoFunctionService: CryptoFunctionService,
|
||||
environmentService: EnvironmentService,
|
||||
keyConnectorService: KeyConnectorService,
|
||||
stateService: StateService
|
||||
environmentService: EnvironmentService,
|
||||
stateService: StateService,
|
||||
twoFactorService: TwoFactorService
|
||||
) {
|
||||
super(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
vaultTimeoutService,
|
||||
logService,
|
||||
cryptoFunctionService,
|
||||
keyConnectorService,
|
||||
environmentService,
|
||||
stateService,
|
||||
false
|
||||
twoFactorService
|
||||
);
|
||||
}
|
||||
|
||||
async logInApiKey(clientId: string, clientSecret: string): Promise<AuthResult> {
|
||||
this.selectedTwoFactorProviderType = null;
|
||||
if (clientId.startsWith("organization")) {
|
||||
return await this.organizationLogInHelper(clientId, clientSecret);
|
||||
}
|
||||
return await super.logInApiKey(clientId, clientSecret);
|
||||
}
|
||||
|
||||
private async organizationLogInHelper(clientId: string, clientSecret: string) {
|
||||
const appId = await this.appIdService.getAppId();
|
||||
const entityId = clientId.split("organization.")[1];
|
||||
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
|
||||
const request = new TokenRequest(
|
||||
null,
|
||||
null,
|
||||
[clientId, clientSecret],
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
deviceRequest
|
||||
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
|
||||
);
|
||||
|
||||
const response = await this.apiService.postIdentityToken(request);
|
||||
const result = new AuthResult();
|
||||
result.twoFactor = !(response as any).accessToken;
|
||||
|
||||
const tokenResponse = response as IdentityTokenResponse;
|
||||
result.resetMasterPassword = tokenResponse.resetMasterPassword;
|
||||
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(),
|
||||
})
|
||||
);
|
||||
return result;
|
||||
return strategy.logIn(credentials);
|
||||
}
|
||||
}
|
||||
|
||||
42
src/services/noop/noopTwoFactor.service.ts
Normal file
42
src/services/noop/noopTwoFactor.service.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
TwoFactorProviderDetails,
|
||||
TwoFactorService,
|
||||
} from "jslib-common/abstractions/twoFactor.service";
|
||||
|
||||
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
|
||||
|
||||
import { IdentityTwoFactorResponse } from "jslib-common/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