## 🚀 Feature Proposal

#7753 added basic support for WebAuthn automation in the form of the `addVirtualAuthenticator` and `removeVirtualAuthenticator` methods. Implement the rest of the methods: `addCredential`, `getCredential`, `removeCredential`, `removeAllCredentials`, `setUserVerified`.

## Motivation

Support more WebAuthn use-cases, like logging in with a specific credential, handling user verification failures, and inspecting generated credentials.

## Example

For a page like this

```html
<button id="login">Log in with WebAuthn</button>
<span id="result"></span>
```

```javascript
document.getElmentById("login").addEventListener("click", () => {
  navigator.credentials.get({...}).then(assertion => {
    document.getElementById("result").innerText = "Success!";
  })
});
```

A test could be written like so:

```java
// Set up the virtual authenticator.
HasVirtualAuthenticator virtualAuthenticatorManager = ((HasVirtualAuthenticator) driver);
VirtualAuthenticatorOptions options = new VirtualAuthenticatorOptions();
VirtualAuthenticator authenticator =
    virtualAuthenticatorManager.addVirtualAuthenticator(options);

// New code: inject a credential into the authenticator.
// Without this API the developer would have to generate a credential through
// navigator.credentials.create({...}) on the javascript side and would have less
// control over the resulting PK.
Credential credential = Credential.createNonResidentCredential(...params);
virtualAuthenticatorManager.addCredential(authenticator, credential);

// Assert login successful:
driver.findElement(By.id("login")).click();
WebElement result = driver.findElement(By.id("result"));
new WebDriverWait(driver, 60, 1000).until(
    driver -> !result.getText().equals(""));
assertThat(result.getText()).isEqualTo("Success!");
```
private static final Splitter PATH_SPLITTER = Splitter.on('/').omitEmptyStrings();
  private static final String SESSION_ID_PARAM = "sessionId";
  private final ConcurrentHashMap<String, CommandSpec> nameToSpec = new ConcurrentHashMap<>();
  private final Map<String, String> aliases = new HashMap<>();
  private final Json json = new Json();
  public AbstractHttpCommandCodec() {
    defineCommand(STATUS, get("/status"));
    defineCommand(GET_ALL_SESSIONS, get("/sessions"));
    defineCommand(NEW_SESSION, post("/session"));
    defineCommand(GET_CAPABILITIES, get("/session/:sessionId"));
    defineCommand(QUIT, delete("/session/:sessionId"));
    defineCommand(GET_SESSION_LOGS, post("/logs"));
    defineCommand(GET_LOG, post("/session/:sessionId/log"));
    defineCommand(GET_AVAILABLE_LOG_TYPES, get("/session/:sessionId/log/types"));
    defineCommand(SWITCH_TO_FRAME, post("/session/:sessionId/frame"));
    defineCommand(SWITCH_TO_PARENT_FRAME, post("/session/:sessionId/frame/parent"));
    defineCommand(CLOSE, delete("/session/:sessionId/window"));
    defineCommand(SWITCH_TO_WINDOW, post("/session/:sessionId/window"));
    defineCommand(SWITCH_TO_NEW_WINDOW, post("/session/:sessionId/window/new"));
    defineCommand(FULLSCREEN_CURRENT_WINDOW, post("/session/:sessionId/window/fullscreen"));
    defineCommand(GET_CURRENT_URL, get("/session/:sessionId/url"));
    defineCommand(GET, post("/session/:sessionId/url"));
    defineCommand(GO_BACK, post("/session/:sessionId/back"));
    defineCommand(GO_FORWARD, post("/session/:sessionId/forward"));