PM-4877: Only allow replacing passkeys for the same userhandle (#9804)
* Initial draft * small cleanup * show vaul items without passkeys * Refactored a bit * tests run for me? * Fixed platform test * null and undefined * lint
This commit is contained in:
parent
aa8c5b1516
commit
dbc9b9c90b
|
@ -65,6 +65,7 @@ export type BrowserFido2Message = { sessionId: string } & (
|
||||||
type: "ConfirmNewCredentialRequest";
|
type: "ConfirmNewCredentialRequest";
|
||||||
credentialName: string;
|
credentialName: string;
|
||||||
userName: string;
|
userName: string;
|
||||||
|
userHandle: string;
|
||||||
userVerification: boolean;
|
userVerification: boolean;
|
||||||
fallbackSupported: boolean;
|
fallbackSupported: boolean;
|
||||||
rpId: string;
|
rpId: string;
|
||||||
|
@ -242,6 +243,7 @@ export class BrowserFido2UserInterfaceSession implements Fido2UserInterfaceSessi
|
||||||
async confirmNewCredential({
|
async confirmNewCredential({
|
||||||
credentialName,
|
credentialName,
|
||||||
userName,
|
userName,
|
||||||
|
userHandle,
|
||||||
userVerification,
|
userVerification,
|
||||||
rpId,
|
rpId,
|
||||||
}: NewCredentialParams): Promise<{ cipherId: string; userVerified: boolean }> {
|
}: NewCredentialParams): Promise<{ cipherId: string; userVerified: boolean }> {
|
||||||
|
@ -250,6 +252,7 @@ export class BrowserFido2UserInterfaceSession implements Fido2UserInterfaceSessi
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
credentialName,
|
credentialName,
|
||||||
userName,
|
userName,
|
||||||
|
userHandle,
|
||||||
userVerification,
|
userVerification,
|
||||||
fallbackSupported: this.fallbackSupported,
|
fallbackSupported: this.fallbackSupported,
|
||||||
rpId,
|
rpId,
|
||||||
|
|
|
@ -143,8 +143,10 @@ export class Fido2Component implements OnInit, OnDestroy {
|
||||||
this.ciphers = (await this.cipherService.getAllDecrypted()).filter(
|
this.ciphers = (await this.cipherService.getAllDecrypted()).filter(
|
||||||
(cipher) => cipher.type === CipherType.Login && !cipher.isDeleted,
|
(cipher) => cipher.type === CipherType.Login && !cipher.isDeleted,
|
||||||
);
|
);
|
||||||
this.displayedCiphers = this.ciphers.filter((cipher) =>
|
this.displayedCiphers = this.ciphers.filter(
|
||||||
cipher.login.matchesUri(this.url, equivalentDomains),
|
(cipher) =>
|
||||||
|
cipher.login.matchesUri(this.url, equivalentDomains) &&
|
||||||
|
this.hasNoOtherPasskeys(cipher, message.userHandle),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.displayedCiphers.length > 0) {
|
if (this.displayedCiphers.length > 0) {
|
||||||
|
@ -405,4 +407,18 @@ export class Fido2Component implements OnInit, OnDestroy {
|
||||||
...msg,
|
...msg,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This methods returns true if a cipher either has no passkeys, or has a passkey matching with userHandle
|
||||||
|
* @param userHandle
|
||||||
|
*/
|
||||||
|
private hasNoOtherPasskeys(cipher: CipherView, userHandle: string): boolean {
|
||||||
|
if (cipher.login.fido2Credentials == null || cipher.login.fido2Credentials.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cipher.login.fido2Credentials.some((passkey) => {
|
||||||
|
passkey.userHandle === userHandle;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,11 @@ export interface NewCredentialParams {
|
||||||
*/
|
*/
|
||||||
userName: string;
|
userName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The userhandle (userid) of the user.
|
||||||
|
*/
|
||||||
|
userHandle: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the user must be verified before completing the operation.
|
* Whether or not the user must be verified before completing the operation.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -215,6 +215,7 @@ describe("FidoAuthenticatorService", () => {
|
||||||
expect(userInterfaceSession.confirmNewCredential).toHaveBeenCalledWith({
|
expect(userInterfaceSession.confirmNewCredential).toHaveBeenCalledWith({
|
||||||
credentialName: params.rpEntity.name,
|
credentialName: params.rpEntity.name,
|
||||||
userName: params.userEntity.name,
|
userName: params.userEntity.name,
|
||||||
|
userHandle: Fido2Utils.bufferToString(params.userEntity.id),
|
||||||
userVerification,
|
userVerification,
|
||||||
rpId: params.rpEntity.id,
|
rpId: params.rpEntity.id,
|
||||||
} as NewCredentialParams);
|
} as NewCredentialParams);
|
||||||
|
|
|
@ -112,6 +112,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
|
||||||
const response = await userInterfaceSession.confirmNewCredential({
|
const response = await userInterfaceSession.confirmNewCredential({
|
||||||
credentialName: params.rpEntity.name,
|
credentialName: params.rpEntity.name,
|
||||||
userName: params.userEntity.name,
|
userName: params.userEntity.name,
|
||||||
|
userHandle: Fido2Utils.bufferToString(params.userEntity.id),
|
||||||
userVerification: params.requireUserVerification,
|
userVerification: params.requireUserVerification,
|
||||||
rpId: params.rpEntity.id,
|
rpId: params.rpEntity.id,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue