Commit ad834d55 authored by Nina Satragno's avatar Nina Satragno Committed by Commit Bot

[chromedriver] Add RemoveAllCredentials WebAuthn command

Add the `RemoveAllCredentials` WebAuthn command to ChromeDriver.

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: I2fd4ec95163487f955b746db8044f98aa9dd90db
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1761484Reviewed-by: default avatarJohn Chen <johnchen@chromium.org>
Commit-Queue: Nina Satragno <nsatragno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#688700}
parent 7293c74a
...@@ -667,3 +667,7 @@ class ChromeDriver(object): ...@@ -667,3 +667,7 @@ class ChromeDriver(object):
def GetCredentials(self, authenticatorId): def GetCredentials(self, authenticatorId):
params = {'authenticatorId': authenticatorId} params = {'authenticatorId': authenticatorId}
return self.ExecuteCommand(Command.GET_CREDENTIALS, params) return self.ExecuteCommand(Command.GET_CREDENTIALS, params)
def RemoveAllCredentials(self, authenticatorId):
params = {'authenticatorId': authenticatorId}
return self.ExecuteCommand(Command.REMOVE_ALL_CREDENTIALS, params)
...@@ -179,6 +179,9 @@ class Command(object): ...@@ -179,6 +179,9 @@ class Command(object):
GET_CREDENTIALS = ( GET_CREDENTIALS = (
_Method.GET, _Method.GET,
'/session/:sessionId/webauthn/authenticator/:authenticatorId/credentials') '/session/:sessionId/webauthn/authenticator/:authenticatorId/credentials')
REMOVE_ALL_CREDENTIALS = (
_Method.DELETE,
'/session/:sessionId/webauthn/authenticator/:authenticatorId/credentials')
# Custom Chrome commands. # Custom Chrome commands.
IS_LOADING = (_Method.GET, '/session/:sessionId/is_loading') IS_LOADING = (_Method.GET, '/session/:sessionId/is_loading')
......
...@@ -777,6 +777,15 @@ HttpHandler::HttpHandler( ...@@ -777,6 +777,15 @@ HttpHandler::HttpHandler(
base::BindRepeating( base::BindRepeating(
&ExecuteWebAuthnCommand, &ExecuteWebAuthnCommand,
base::BindRepeating(&ExecuteGetCredentials)))), base::BindRepeating(&ExecuteGetCredentials)))),
CommandMapping(
kDelete,
"session/:sessionId/webauthn/authenticator/:authenticatorId/"
"credentials",
WrapToCommand(
"RemoveAllCredentials",
base::BindRepeating(
&ExecuteWebAuthnCommand,
base::BindRepeating(&ExecuteRemoveAllCredentials)))),
// //
// Non-standard extension commands // Non-standard extension commands
......
...@@ -227,6 +227,7 @@ _ANDROID_NEGATIVE_FILTER['chrome'] = ( ...@@ -227,6 +227,7 @@ _ANDROID_NEGATIVE_FILTER['chrome'] = (
'ChromeDriverSecureContextTest.testRemoveVirtualAuthenticator', 'ChromeDriverSecureContextTest.testRemoveVirtualAuthenticator',
'ChromeDriverSecureContextTest.testAddCredential', 'ChromeDriverSecureContextTest.testAddCredential',
'ChromeDriverSecureContextTest.testGetCredentials', 'ChromeDriverSecureContextTest.testGetCredentials',
'ChromeDriverSecureContextTest.testRemoveAllCredentials',
# Covered by Desktop tests; can't create 2 browsers in Android # Covered by Desktop tests; can't create 2 browsers in Android
'SupportIPv4AndIPv6.testSupportIPv4AndIPv6', 'SupportIPv4AndIPv6.testSupportIPv4AndIPv6',
] ]
...@@ -2023,7 +2024,9 @@ class ChromeDriverSecureContextTest(ChromeDriverBaseTest): ...@@ -2023,7 +2024,9 @@ class ChromeDriverSecureContextTest(ChromeDriverBaseTest):
# The example attestation private key from the U2F spec at # The example attestation private key from the U2F spec at
# https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-example # https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-example
# PKCS.8 encoded without encryption, as a base64url string. # PKCS.8 encoded without encryption, as a base64url string.
privateKey = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Qhk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwURmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB" privateKey = ("MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q"
"hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU"
"RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB")
@staticmethod @staticmethod
def GlobalSetUp(): def GlobalSetUp():
...@@ -2197,6 +2200,48 @@ class ChromeDriverSecureContextTest(ChromeDriverBaseTest): ...@@ -2197,6 +2200,48 @@ class ChromeDriverSecureContextTest(ChromeDriverBaseTest):
self.assertEquals(1, credentials[0]['signCount']) self.assertEquals(1, credentials[0]['signCount'])
self.assertTrue(credentials[0]['privateKey']) self.assertTrue(credentials[0]['privateKey'])
def testRemoveAllCredentials(self):
register_credential_script = """
let done = arguments[0];
registerCredential().then(done);
"""
self._driver.Load(self.GetHttpsUrlForFile(
'/chromedriver/webauthn_test.html', 'chromedriver.test'))
authenticatorId = self._driver.AddVirtualAuthenticator(
protocol = 'ctap2',
transport = 'usb',
hasResidentKey = True,
hasUserVerification = True,
)['authenticatorId']
# Register a credential via the webauthn API.
result = self._driver.ExecuteAsyncScript(register_credential_script)
self.assertEquals('OK', result['status'])
credentialId = result['credential']['rawId']
# Attempting to register with the credential ID on excludeCredentials should
# fail.
exclude_credentials_script = """
let done = arguments[0];
registerCredential({
excludeCredentials: [{
type: "public-key",
id: Uint8Array.from(%s),
transports: ["usb"],
}],
}).then(done);
""" % (credentialId)
result = self._driver.ExecuteAsyncScript(exclude_credentials_script)
self.assertEquals("InvalidStateError: The user attempted to register an "
"authenticator that contains one of the credentials "
"already registered with the relying party.",
result['status'])
# The registration should succeed after clearing the credentials.
self._driver.RemoveAllCredentials(authenticatorId)
result = self._driver.ExecuteAsyncScript(exclude_credentials_script)
self.assertEquals('OK', result['status'])
# Tests in the following class are expected to be moved to ChromeDriverTest # Tests in the following class are expected to be moved to ChromeDriverTest
# class when we no longer support the legacy mode. # class when we no longer support the legacy mode.
class ChromeDriverW3cTest(ChromeDriverBaseTestWithWebServer): class ChromeDriverW3cTest(ChromeDriverBaseTestWithWebServer):
......
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
#include "chrome/test/chromedriver/webauthn_commands.h" #include "chrome/test/chromedriver/webauthn_commands.h"
#include <string>
#include <utility> #include <utility>
#include <vector>
#include "base/base64.h" #include "base/base64.h"
#include "base/base64url.h" #include "base/base64url.h"
...@@ -162,3 +164,11 @@ Status ExecuteGetCredentials(WebView* web_view, ...@@ -162,3 +164,11 @@ Status ExecuteGetCredentials(WebView* web_view,
return status; return status;
} }
Status ExecuteRemoveAllCredentials(WebView* web_view,
const base::Value& params,
std::unique_ptr<base::Value>* value) {
return web_view->SendCommandAndGetResult(
"WebAuthn.clearCredentials",
MapParams({{"authenticatorId", "authenticatorId"}}, params), value);
}
...@@ -49,4 +49,9 @@ Status ExecuteGetCredentials(WebView* web_view, ...@@ -49,4 +49,9 @@ Status ExecuteGetCredentials(WebView* web_view,
const base::Value& params, const base::Value& params,
std::unique_ptr<base::Value>* value); std::unique_ptr<base::Value>* value);
// Remove all the credentials stored in an authenticator.
Status ExecuteRemoveAllCredentials(WebView* web_view,
const base::Value& params,
std::unique_ptr<base::Value>* value);
#endif // CHROME_TEST_CHROMEDRIVER_WEBAUTHN_COMMANDS_H_ #endif // CHROME_TEST_CHROMEDRIVER_WEBAUTHN_COMMANDS_H_
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