Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WebDriver commands #465

Merged
merged 8 commits into from
May 16, 2023
Merged
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 268 additions & 6 deletions spec/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ spec: credential-management-1; urlPrefix: https://w3c.github.io/webappsec-creden
text: same-origin with its ancestors; url: same-origin-with-its-ancestors
type: dfn
text: requires user mediation; url: origin-requires-user-mediation
spec: webdriver; urlPrefix: https://w3c.github.io/webdriver/
cbiesinger marked this conversation as resolved.
Show resolved Hide resolved
type: dfn
text: getting a property; url: dfn-getting-properties
text: no such alert; url: dfn-no-such-alert
text: error code; url: dfn-error-code
</pre>

<pre class=link-defaults>
Expand All @@ -39,6 +44,7 @@ spec:infra; type:dfn; text:user agent
spec:html; type:dfn; for:environment settings object; text:global object
spec:html; type:dfn; for:html-origin-def; text:origin
spec:webidl; type:dfn; text:resolve
spec:webdriver2; type:dfn; text:error
</pre>

<style>
Expand Down Expand Up @@ -463,7 +469,7 @@ This [=internal method=] accepts three arguments:
The |options|.{{CredentialRequestOptions/signal}} is used as an abort signal for the
requests.

<div algorithm>
<div algorithm="[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)">
When the {{IdentityCredential}}'s
<dfn for="IdentityCredential" method>\[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)</dfn>
algorithm is invoked, the user agent MUST execute the following steps. This returns an
Expand Down Expand Up @@ -492,10 +498,12 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu
|options|["{{CredentialRequestOptions/mediation}}"], and |globalObject|.
1. If |credential| is a pair:
1. Let |throwImmediately| be the value of the second element of the pair.
1. If |throwImmediately| is false, the user agent SHOULD wait a random
amount of time before the next step, unless it has implemented
another way to prevent exposing to the RP whether the user has
an account logged in to the RP.
1. If |throwImmediately| is false, and this <dfn>promise rejection
cbiesinger marked this conversation as resolved.
Show resolved Hide resolved
delay</dfn> was not disabled by [=setdelayenabled|user agent
automation=], the user agent SHOULD wait a random amount of time
before the next step, unless it has implemented another way to
prevent exposing to the RP whether the user has an account logged
in to the RP.

Note: The intention here is as follows. If we resolved the promise immediately,
then an RP could infer that no dialog was shown because the promise was
Expand Down Expand Up @@ -553,7 +561,7 @@ the exception thrown.
1. Set |account| to |registeredAccount| and |accountState| to the result of running
[=compute account state=] algorithm given |provider| and |account|. When doing this,
the user agent MAY show some UI to the user indicating that they are being
auto-reauthenticated.
<dfn>auto-reauthenticated</dfn>.
1. Otherwise, if |mediation| is "{{CredentialMediationRequirement/silent}}", return failure.
1. Otherwise, if |accountsList|'s size is 1:
1. Set |account| to |accountsList|[0].
Expand Down Expand Up @@ -1456,6 +1464,260 @@ occur when there is access to the [=current settings object=]. The [=internal me
modified by this specification do not have such access since they are invoked [=in parallel=]
by {{CredentialsContainer}}'s <a abstract-op>Request a `Credential`</a> abstract operation.

<!-- ============================================================ -->
# User Agent Automation # {#automation}
<!-- ============================================================ -->

For the purposes of user agent automation and website testing, this document
defines the below [[WebDriver2]] [=extension commands=] to interact with any
active FedCM dialogs.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we add a subsection for each remote end step. Right now it's unclear what you're defining in each case unless you look at the POST closely. It could be in a title.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand how the behavior is limited in terms of interaction to make sure it cannot be exploited. Or is that a question for later?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the concern. Webdriver APIs are not exposed to the web (and also not enabled by default). See, for example, https://chromedriver.chromium.org/security-considerations

There are lots of ways webdriver can be exploited if that weren't the case since the APIs are very powerful.

This is only meant to be used by local automation/testing tools

## Cancel dialog ## {#webdriver-canceldialog}

<figure id="table-webdriver-canceldialog" class="table">
<table class="data">
<thead>
<tr>
<th>HTTP Method</th>
<th>URI Template</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td>`/session/{session id}/fedcm/canceldialog`</td>
</tr>
</tbody>
</table>
</figure>

The [=remote end steps=] are:

1. If no FedCM dialog is currently open, return a [=error|WebDriver error=] with
[=error code=] [=no such alert=].

1. Close the dialog and continue the [=create an IdentityCredential=] algorithm
as if the user had canceled the dialog without choosing an account.

1. Return [=success=] with data `null`.

## Select account ## {#webdriver-selectaccount}

<figure id="table-webdriver-selectaccount" class="table">
<table class="data">
<thead>
<tr>
<th>HTTP Method</th>
<th>URI Template</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td>`/session/{session id}/fedcm/selectaccount`</td>
</tr>
</tbody>
</table>
</figure>

The [=remote end steps=] are:

1. If |parameters| is not a JSON [[ECMASCRIPT#sec-json-object|Object]], return a
[=error|WebDriver error=] with [=error code=] [=invalid argument=].

1. If no FedCM dialog is currently open, return a [=error|WebDriver error=] with
[=error code=] [=no such alert=].

1. Let |accountIndex| be the result of [=getting a property=] named `"accountIndex"`
from |parameters|.

1. If |accountIndex| is {{undefined}} or is less than 0 or greater than or
equal to the number of accounts that the user can choose from in the
current flow, return a [=error|WebDriver error=] with [=error code=]
[=invalid argument=].

1. Close the dialog and continue the [=create an IdentityCredential=] algorithm
as if the user had selected the account indicated by |accountIndex| and
[=request permission to sign-up|granted permission to sign-up=], if applicable.

1. Return [=success=] with data `null`.

## Account list ## {#webdriver-accountlist}

<figure id="table-webdriver-accountlist" class="table">
<table class="data">
<thead>
<tr>
<th>HTTP Method</th>
<th>URI Template</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td>`/session/{session id}/fedcm/accountlist`</td>
</tr>
</tbody>
</table>
</figure>

The [=remote end steps=] are:

1. If no FedCM dialog is currently open, return a [=error|WebDriver error=] with
[=error code=] [=no such alert=].

1. Let |accounts| be the list of accounts that the user can or could choose
from in the current flow.

1. Let |list| be an empty list.

1. For each |account| in |accounts|:
1. Let |accountState| be the result of running the [=compute account state=]
algorithm given |account|
1. [=list/Append=] a [=dictionary=] to |list| with the following properties:
1. `accountId` set to the account's {{IdentityProviderAccount/id}}
1. `email` set to the account's {{IdentityProviderAccount/email}}
1. `name` set to the account's {{IdentityProviderAccount/name}}
1. `givenName` set to the account's {{IdentityProviderAccount/given_name}},
if present
1. `pictureUrl` set to the account's {{IdentityProviderAccount/picture}},
if present.
cbiesinger marked this conversation as resolved.
Show resolved Hide resolved
1. `idpConfigUrl` set to the {{IdentityProviderConfig/configURL}} of the
IDP this account belongs to
1. `loginState` to `"SignUp"` if |accountState|'s {{AccountState/registration
state}} is {{unregistered}} and `"SignIn"` otherwise
1. `termsOfServiceUrl` to the {{IdentityProviderClientMetadata/terms_of_service_url}}
npm1 marked this conversation as resolved.
Show resolved Hide resolved
if one was provided and the `loginState` is `"SignUp"`, otherwise {{undefined}}
1. `privacyPolicyUrl` to the {{IdentityProviderClientMetadata/privacy_policy_url}}
if one was provided and the `loginState` is `"SignUp"`, otherwise {{undefined}}

1. Return [=success=] with data |list|.

## Get title ## {#webdriver-gettitle}

<figure id="table-webdriver-gettitle" class="table">
<table class="data">
<thead>
<tr>
<th>HTTP Method</th>
<th>URI Template</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td>`/session/{session id}/fedcm/gettitle`</td>
</tr>
</tbody>
</table>
</figure>

Note: This command lets automation verify that the
[context api](https://github.com/fedidcg/FedCM/blob/main/proposals/context-api.md)
was applied properly

The [=remote end steps=] are:

1. If no FedCM dialog is currently open, return a [=error|WebDriver error=] with
[=error code=] [=no such alert=].

1. Let |data| be a dictionary with an object with properties as follows:
1. `title` set to the title of the open dialog
1. `subtitle` set to the subtitle of the open dialog, if there is one

1. Return [=success=] with data |data|.

## Get dialog type ## {#webdriver-getdialogtype}

<figure id="table-webdriver-getdialogtype" class="table">
<table class="data">
<thead>
<tr>
<th>HTTP Method</th>
<th>URI Template</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td>`/session/{session id}/fedcm/getdialogtype`</td>
</tr>
</tbody>
</table>
</figure>

The [=remote end steps=] are:

1. If no FedCM dialog is currently open, return a [=error|WebDriver error=] with
[=error code=] [=no such alert=].

1. Let |type| be a string that is "`AutoReauthn`" if the user is being [=auto-reauthenticated=],
or "`AccountChooser`" otherwise.

1. Return [=success=] with data |type|.

## Set delay enabled ## {#webdriver-setdelayenabled}

<figure id="table-webdriver-setdelayenabled" class="table">
<table class="data">
<thead>
<tr>
<th>HTTP Method</th>
<th>URI Template</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td>`/session/{session id}/fedcm/`<dfn>`setdelayenabled`</dfn></td>
</tr>
</tbody>
</table>
</figure>

The [=remote end steps=] are:

1. If |parameters| is not a JSON [[ECMASCRIPT#sec-json-object|Object]], return a
[=error|WebDriver error=] with [=error code=] [=invalid argument=].

1. Let |enabled| be the result of [=getting a property=] named `"enabled"` from
|parameters|.

1. If |enabled| is {{undefined}} or is not a boolean, return a [=error|WebDriver error=]
with [=error code=] [=invalid argument=].

1. If |enabled| is false, disables the [=promise rejection delay=]; otherwise,
re-enables it.

1. Return [=success=] with data `null`.

## Reset cooldown ## {#webdriver-resetcooldown}

<figure id="table-webdriver-resetcooldown" class="table">
<table class="data">
<thead>
<tr>
<th>HTTP Method</th>
<th>URI Template</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td>`/session/{session id}/fedcm/resetcooldown`</td>
</tr>
</tbody>
</table>
</figure>

The [=remote end steps=] are:

1. If the user agent uses a cooldown delay, which disables the API for an
amount of time after the user dismissed the dialog, then this command
resets that cooldown such that the next FedCM call can succeed again.

1. Return [=success=] with data `null`.

<!-- ============================================================ -->
# Security # {#security}
<!-- ============================================================ -->
Expand Down