1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-27 01:53:23 +00:00

show key connector domain for new sso users

This commit is contained in:
Maciej Zieniuk
2025-04-03 16:22:17 +01:00
parent a10cd49e53
commit 8538614d75
16 changed files with 199 additions and 32 deletions

View File

@@ -77,7 +77,10 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
return super.logInTwoFactor(twoFactor);
}
protected override async setMasterKey(response: IdentityTokenResponse, userId: UserId) {
protected override async setMasterKey(
response: IdentityTokenResponse,
userId: UserId,
): Promise<null> {
const authRequestCredentials = this.cache.value.authRequestCredentials;
if (
authRequestCredentials.decryptedMasterKey &&
@@ -92,6 +95,8 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
userId,
);
}
return null;
}
protected override async setUserKey(

View File

@@ -296,7 +296,12 @@ export abstract class LoginStrategy {
await this.tokenService.setTwoFactorToken(userEmail, response.twoFactorToken);
}
await this.setMasterKey(response, userId);
const masterKeyResult = await this.setMasterKey(response, userId);
if (masterKeyResult != null) {
result.requiresKeyConnectorDomainConfirmation =
masterKeyResult.requiresKeyConnectorDomainConfirmation;
}
await this.setUserKey(response, userId);
await this.setPrivateKey(response, userId);
@@ -306,7 +311,19 @@ export abstract class LoginStrategy {
}
// The keys comes from different sources depending on the login strategy
protected abstract setMasterKey(response: IdentityTokenResponse, userId: UserId): Promise<void>;
protected abstract setMasterKey(
response: IdentityTokenResponse,
userId: UserId,
): Promise<{
requiresKeyConnectorDomainConfirmation: {
kdf: KdfType;
kdfIterations: number;
kdfMemory?: number;
kdfParallelism?: number;
keyConnectorUrl: string;
organizationId: string;
};
} | null>;
protected abstract setUserKey(response: IdentityTokenResponse, userId: UserId): Promise<void>;

View File

@@ -168,10 +168,15 @@ export class PasswordLoginStrategy extends LoginStrategy {
return result;
}
protected override async setMasterKey(response: IdentityTokenResponse, userId: UserId) {
protected override async setMasterKey(
response: IdentityTokenResponse,
userId: UserId,
): Promise<null> {
const { masterKey, localMasterKeyHash } = this.cache.value;
await this.masterPasswordService.setMasterKey(masterKey, userId);
await this.masterPasswordService.setMasterKeyHash(localMasterKeyHash, userId);
return null;
}
protected override async setUserKey(

View File

@@ -125,16 +125,23 @@ export class SsoLoginStrategy extends LoginStrategy {
// The presence of a masterKeyEncryptedUserKey indicates that the user has already been provisioned in Key Connector.
const newSsoUser = tokenResponse.key == null;
if (newSsoUser) {
await this.keyConnectorService.convertNewSsoUserToKeyConnector(
tokenResponse,
this.cache.value.orgId,
userId,
);
return {
requiresKeyConnectorDomainConfirmation: {
kdf: tokenResponse.kdf,
kdfIterations: tokenResponse.kdfIterations,
kdfMemory: tokenResponse.kdfMemory,
kdfParallelism: tokenResponse.kdfParallelism,
keyConnectorUrl: this.getKeyConnectorUrl(tokenResponse),
organizationId: this.cache.value.orgId,
},
};
} else {
const keyConnectorUrl = this.getKeyConnectorUrl(tokenResponse);
await this.keyConnectorService.setMasterKeyFromUrl(keyConnectorUrl, userId);
}
}
return null;
}
/**
@@ -211,7 +218,7 @@ export class SsoLoginStrategy extends LoginStrategy {
this.getKeyConnectorUrl(tokenResponse) != null
) {
// Key connector enabled for user
await this.trySetUserKeyWithMasterKey(userId);
await this.trySetUserKeyWithMasterKey(tokenResponse, userId);
}
// Note: In the traditional SSO flow with MP without key connector, the lock component
@@ -321,7 +328,17 @@ export class SsoLoginStrategy extends LoginStrategy {
}
}
private async trySetUserKeyWithMasterKey(userId: UserId): Promise<void> {
private async trySetUserKeyWithMasterKey(
tokenResponse: IdentityTokenResponse,
userId: UserId,
): Promise<void> {
const newSsoUser = tokenResponse.key == null;
// For new users with Key Connector, we will not have a master key yet, since Key Connector
// domain have to be confirmed first.
if (newSsoUser) {
return;
}
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
// There is a scenario in which the master key is not set here. That will occur if the user

View File

@@ -52,12 +52,16 @@ export class UserApiLoginStrategy extends LoginStrategy {
return authResult;
}
protected override async setMasterKey(response: IdentityTokenResponse, userId: UserId) {
protected override async setMasterKey(
response: IdentityTokenResponse,
userId: UserId,
): Promise<null> {
if (response.apiUseKeyConnector) {
const env = await firstValueFrom(this.environmentService.environment$);
const keyConnectorUrl = env.getKeyConnectorUrl();
await this.keyConnectorService.setMasterKeyFromUrl(keyConnectorUrl, userId);
}
return null;
}
protected override async setUserKey(

View File

@@ -59,8 +59,11 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
throw new Error("2FA not supported yet for WebAuthn Login.");
}
protected override async setMasterKey(response: IdentityTokenResponse, userId: UserId) {
return Promise.resolve();
protected override async setMasterKey(
response: IdentityTokenResponse,
userId: UserId,
): Promise<null> {
return null;
}
protected override async setUserKey(idTokenResponse: IdentityTokenResponse, userId: UserId) {