move extension launchSsoBrowserWindow() to extension service

This commit is contained in:
rr-bw 2024-09-13 17:21:15 -07:00
parent b7996183bf
commit e076e94c08
No known key found for this signature in database
GPG Key ID: 3FA13C3ADEE51D5D
6 changed files with 88 additions and 54 deletions

View File

@ -1,9 +1,73 @@
import { inject } from "@angular/core";
import { firstValueFrom } from "rxjs";
import { DefaultLoginService, LoginService } from "@bitwarden/auth/angular";
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import { flagEnabled } from "../../../platform/flags"; // TODO-rr-bw: do I need a client specific `flagEnabled()` fn?
export class ExtensionLoginService extends DefaultLoginService implements LoginService {
ssoLoginService = inject(SsoLoginServiceAbstraction);
passwordGenerationService = inject(PasswordGenerationServiceAbstraction);
cryptoFunctionService = inject(CryptoFunctionService);
environmentService = inject(EnvironmentService);
platformUtilsService = inject(PlatformUtilsService);
getShowPasswordlessFlag(): boolean {
return flagEnabled("showPasswordless");
}
async launchSsoBrowserWindow(email: string): Promise<void | null> {
// Save off email for SSO
await this.ssoLoginService.setSsoEmail(email);
// Generate necessary sso params
const passwordOptions: any = {
type: "password",
length: 64,
uppercase: true,
lowercase: true,
numbers: true,
special: false,
};
const state =
(await this.passwordGenerationService.generatePassword(passwordOptions)) +
":clientId=browser";
const codeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions);
const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, "sha256");
const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
await this.ssoLoginService.setCodeVerifier(codeVerifier);
await this.ssoLoginService.setSsoState(state);
const env = await firstValueFrom(this.environmentService.environment$);
let url = env.getWebVaultUrl();
if (url == null) {
url = "https://vault.bitwarden.com";
}
const redirectUri = url + "/sso-connector.html";
// Launch browser
this.platformUtilsService.launchUri(
url +
"/#/sso?clientId=browser" +
"&redirectUri=" +
encodeURIComponent(redirectUri) +
"&state=" +
state +
"&codeChallenge=" +
codeChallenge +
"&email=" +
encodeURIComponent(email),
);
}
}

View File

@ -16,7 +16,7 @@ import {
CLIENT_TYPE,
} from "@bitwarden/angular/services/injection-tokens";
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
import { AnonLayoutWrapperDataService } from "@bitwarden/auth/angular";
import { AnonLayoutWrapperDataService, LoginService } from "@bitwarden/auth/angular";
import { PinServiceAbstraction } from "@bitwarden/auth/common";
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
@ -92,6 +92,7 @@ import { DialogService, ToastService } from "@bitwarden/components";
import { PasswordRepromptService } from "@bitwarden/vault";
import { ExtensionAnonLayoutWrapperDataService } from "../../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service";
import { ExtensionLoginService } from "../../auth/popup/login/extension-login.service";
import { AutofillService as AutofillServiceAbstraction } from "../../autofill/services/abstractions/autofill.service";
import AutofillService from "../../autofill/services/autofill.service";
import MainBackground from "../../background/main.background";
@ -560,6 +561,11 @@ const safeProviders: SafeProvider[] = [
useClass: ExtensionAnonLayoutWrapperDataService,
deps: [],
}),
safeProvider({
provide: LoginService,
useClass: ExtensionLoginService,
deps: [I18nServiceAbstraction, ToastService],
}),
];
@NgModule({

View File

@ -11,6 +11,10 @@ export class DefaultLoginService implements LoginService {
protected toastService: ToastService,
) {}
async launchSsoBrowserWindow(email: string): Promise<void | null> {
return null;
}
getShowPasswordlessFlag(): boolean {
return null;
}

View File

@ -150,7 +150,13 @@
<!-- TODO-rr-bw: Figma shows no Login with Passkey option on browser. Is that intentional? -->
<!-- Button to Login with SSO -->
<button type="button" bitButton block buttonType="secondary" (click)="launchSsoBrowser()">
<button
type="button"
bitButton
block
buttonType="secondary"
(click)="launchSsoBrowserWindow()"
>
<i class="bwi bwi-provider tw-mr-1"></i>
{{ "useSingleSignOn" | i18n }}
</button>

View File

@ -16,14 +16,12 @@ import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.d
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { CaptchaIFrame } from "@bitwarden/common/auth/captcha-iframe";
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
import { ClientType } from "@bitwarden/common/enums";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
@ -40,7 +38,6 @@ import {
IconButtonModule,
ToastService,
} from "@bitwarden/components";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import { AnonLayoutWrapperDataService } from "../anon-layout/anon-layout-wrapper-data.service";
import { WaveIcon } from "../icons";
@ -120,7 +117,6 @@ export class LoginComponent implements OnInit, OnDestroy {
private anonLayoutWrapperDataService: AnonLayoutWrapperDataService,
private appIdService: AppIdService,
private broadcasterService: BroadcasterService,
private cryptoFunctionService: CryptoFunctionService,
private devicesApiService: DevicesApiServiceAbstraction,
private environmentService: EnvironmentService,
private formBuilder: FormBuilder,
@ -130,13 +126,11 @@ export class LoginComponent implements OnInit, OnDestroy {
private loginStrategyService: LoginStrategyServiceAbstraction,
private messagingService: MessagingService,
private ngZone: NgZone,
private passwordGenerationService: PasswordGenerationServiceAbstraction,
private passwordStrengthService: PasswordStrengthServiceAbstraction,
private platformUtilsService: PlatformUtilsService,
private policyService: InternalPolicyService,
private registerRouteService: RegisterRouteService,
private router: Router,
private ssoLoginService: SsoLoginServiceAbstraction,
private syncService: SyncService,
private toastService: ToastService,
) {
@ -285,51 +279,8 @@ export class LoginComponent implements OnInit, OnDestroy {
}
}
protected async launchSsoBrowser() {
// Save off email for SSO
await this.ssoLoginService.setSsoEmail(this.formGroup.value.email);
// Generate necessary sso params
const passwordOptions: any = {
type: "password",
length: 64,
uppercase: true,
lowercase: true,
numbers: true,
special: false,
};
const state =
(await this.passwordGenerationService.generatePassword(passwordOptions)) +
":clientId=browser";
const codeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions);
const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, "sha256");
const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
await this.ssoLoginService.setCodeVerifier(codeVerifier);
await this.ssoLoginService.setSsoState(state);
const env = await firstValueFrom(this.environmentService.environment$);
let url = env.getWebVaultUrl();
if (url == null) {
url = "https://vault.bitwarden.com";
}
const redirectUri = url + "/sso-connector.html";
// Launch browser
this.platformUtilsService.launchUri(
url +
"/#/sso?clientId=browser" +
"&redirectUri=" +
encodeURIComponent(redirectUri) +
"&state=" +
state +
"&codeChallenge=" +
codeChallenge +
"&email=" +
encodeURIComponent(this.formGroup.controls.email.value),
);
protected async launchSsoBrowserWindow(): Promise<void> {
await this.loginService.launchSsoBrowserWindow(this.loggedEmail);
}
protected async goAfterLogIn(userId: UserId): Promise<void> {

View File

@ -10,7 +10,10 @@ export interface PasswordPolicies {
}
export abstract class LoginService {
// Web specific
// Browser/Desktop
launchSsoBrowserWindow: (email: string) => Promise<void>;
// Web
getShowPasswordlessFlag: () => boolean;
getOrgPolicies: () => Promise<PasswordPolicies | null>;
setPreviousUrl: (route: UrlTree) => void | null;