Commit 870451a4 authored by Nina Satragno's avatar Nina Satragno Committed by Commit Bot

[webauthn] Add removeCredential to DevTools Domain

This patch adds the `removeCredential` command to the WebAuthn DevTools
Domain. This allows removing a single credential identified by ID.

This is one in a series of patches intended to create a Testing API for
WebAuthn, for use in Web Platform Tests and by external webauthn tests.

For an overview of overall design, please see
https://docs.google.com/document/d/1bp2cMgjm2HSpvL9-WsJoIQMsBi1oKGQY6CvWD-9WmIQ/edit?usp=sharing

Bug: 922572
Change-Id: Idc40416a7be04165729ad03f2902716c922e1e43
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1764517
Commit-Queue: Nina Satragno <nsatragno@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#689496}
parent 30f0f7f9
......@@ -255,6 +255,19 @@ Response WebAuthnHandler::GetCredentials(
return Response::OK();
}
Response WebAuthnHandler::RemoveCredential(const String& authenticator_id,
const Binary& credential_id) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
if (!response.isSuccess())
return response;
if (!authenticator->RemoveRegistration(CopyBinaryToVector(credential_id)))
return Response::InvalidParams(kCredentialNotFound);
return Response::OK();
}
Response WebAuthnHandler::ClearCredentials(const String& authenticator_id) {
VirtualAuthenticator* authenticator;
Response response = FindAuthenticator(authenticator_id, &authenticator);
......
......@@ -45,6 +45,8 @@ class WebAuthnHandler : public DevToolsDomainHandler, public WebAuthn::Backend {
const String& authenticator_id,
std::unique_ptr<protocol::Array<protocol::WebAuthn::Credential>>*
out_credentials) override;
Response RemoveCredential(const String& in_authenticator_id,
const Binary& credential_id) override;
Response ClearCredentials(const String& in_authenticator_id) override;
Response SetUserVerified(const String& authenticator_id,
bool is_user_verified) override;
......
......@@ -102,7 +102,7 @@
},
{
"domain": "WebAuthn",
"include": ["enable", "disable", "addVirtualAuthenticator", "removeVirtualAuthenticator", "addCredential", "clearCredentials", "getCredential", "getCredentials", "setUserVerified"]
"include": ["enable", "disable", "addVirtualAuthenticator", "removeVirtualAuthenticator", "addCredential", "removeCredential", "clearCredentials", "getCredential", "getCredentials", "setUserVerified"]
}
]
},
......
......@@ -82,6 +82,11 @@ void VirtualAuthenticator::ClearRegistrations() {
state_->registrations.clear();
}
bool VirtualAuthenticator::RemoveRegistration(
const std::vector<uint8_t>& key_handle) {
return state_->registrations.erase(key_handle) != 0;
}
void VirtualAuthenticator::SetUserPresence(bool is_user_present) {
is_user_present_ = is_user_present;
state_->simulate_press_callback = base::BindRepeating(
......
......@@ -60,6 +60,10 @@ class CONTENT_EXPORT VirtualAuthenticator
// Removes all the credentials.
void ClearRegistrations();
// Remove a credential identified by |key_handle|. Returns true if the
// credential was found and removed, false otherwise.
bool RemoveRegistration(const std::vector<uint8_t>& key_handle);
// Sets whether tests of user presence succeed or not for new requests sent to
// this authenticator. The default is true.
void SetUserPresence(bool is_user_present);
......
......@@ -7332,6 +7332,12 @@ experimental domain WebAuthn
returns
array of Credential credentials
# Removes a credential from the authenticator.
command removeCredential
parameters
AuthenticatorId authenticatorId
binary credentialId
# Clears all the credentials from the specified device.
command clearCredentials
parameters
......
......@@ -2,6 +2,14 @@
<html lang="en">
<head>
<script>
function base64urlToBase64(base64url) {
let base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
// Add padding to make the length of the base64 string divisible by 4.
if (base64.length % 4 != 0)
base64 += "=".repeat(4 - base64.length % 4);
return base64;
}
function base64ToArrayBuffer(base64) {
return Uint8Array.from(atob(base64), c => c.charCodeAt(0)).buffer;
}
......
......@@ -22,9 +22,8 @@
})`));
testRunner.log(result.status);
// Convert the credential ID from base64url to base64.
let credentialId = result.credential.id.replace(/-/g, "+").replace(/_/g, "/");
credentialId += "=".repeat(4 - credentialId.length % 4);
let credentialId =
await session.evaluate(`base64urlToBase64("${result.credential.id}")`);
// Get the registered credential.
let credential =
......
Check that the WebAuthn command removeCredential works
OK
OK
2
{
id : <number>
result : {
}
sessionId : <string>
}
1
IDs match
(async function(testRunner) {
const {page, session, dp} =
await testRunner.startURL(
"https://devtools.test:8443/inspector-protocol/webauthn/resources/webauthn-test.https.html",
"Check that the WebAuthn command removeCredential works");
await dp.WebAuthn.enable();
const authenticatorId = (await dp.WebAuthn.addVirtualAuthenticator({
options: {
protocol: "ctap2",
transport: "usb",
hasResidentKey: false,
hasUserVerification: false,
},
})).result.authenticatorId;
// Register two credentials.
const result1 = await session.evaluateAsync("registerCredential()");
testRunner.log(result1.status);
let credential1Id =
await session.evaluate(`base64urlToBase64("${result1.credential.id}")`);
const result2 = await session.evaluateAsync("registerCredential()");
testRunner.log(result2.status);
let credential2Id =
await session.evaluate(`base64urlToBase64("${result2.credential.id}")`);
let credentials = (await dp.WebAuthn.getCredentials({authenticatorId})).result.credentials;
testRunner.log(credentials.length);
// Remove the first credential.
testRunner.log(await dp.WebAuthn.removeCredential({
authenticatorId,
credentialId: credential1Id
}));
// Only the second credential should remain.
credentials = (await dp.WebAuthn.getCredentials({authenticatorId})).result.credentials;
testRunner.log(credentials.length);
testRunner.log(
credentials[0].credentialId == credential2Id ? "IDs match" : "IDs do not match");
testRunner.completeTest();
})
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment