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 2 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
241 changes: 239 additions & 2 deletions spec/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ spec: ecma262; urlPrefix: https://tc39.github.io/ecma262/
spec: credential-management-1; urlPrefix: https://w3c.github.io/webappsec-credential-management/
type: dfn
text: same-origin with its ancestors; url: same-origin-with-its-ancestors
spec: webdriver; urlPrefix: https://w3c.github.io/webdriver/
cbiesinger marked this conversation as resolved.
Show resolved Hide resolved
type: dfn
text: extension command; url: dfn-extension-commands
text: getting a property; url: dfn-getting-properties
text: invalid argument; url: dfn-invalid-argument
text: no such alert; url: dfn-no-such-alert
text: remote end steps; url: dfn-remote-end-steps
text: success; url: dfn-success
text: undefined; url: dfn-undefined
text: WebDriver error; url: dfn-error
text: WebDriver error code; url: dfn-error-code
</pre>

<pre class=link-defaults>
Expand Down Expand Up @@ -442,7 +453,7 @@ NOTE: The {{CredentialRequestOptions/mediation}} flag is currently not used.
The {{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 All @@ -454,7 +465,8 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu

Issue: Support choosing accounts from multiple [=IDP=]s, as described [here](https://github.com/fedidcg/FedCM/issues/319).
1. Run {{WindowOrWorkerGlobalScope/setTimeout()}} passing a [=task=] which throws a
{{NetworkError}}, after a timeout of 60 seconds.
{{NetworkError}}, after a timeout of 60 seconds, unless this <dfn>promise rejection
Copy link
Collaborator

Choose a reason for hiding this comment

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

We're not doing this timeout in the implementation, so how is it supposed to work?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's an unfortunate aspect of #453 not having landed yet. Once either PR is pushed I'll update the other one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated this text per the timeout change in #453 .

delay</dfn> was disabled by [=setdelayenabled|user agent automation=].

Issue: Do not use {{WindowOrWorkerGlobalScope/setTimeout()}} directly, as that is not correct. See the relevant
[issue](https://github.com/fedidcg/FedCM/issues/389).
Expand Down Expand Up @@ -1358,6 +1370,231 @@ 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 [=WebDriver error=] with
[=WebDriver 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
[=WebDriver error=] with [=WebDriver error code=] [=invalid argument=].

1. If no FedCM dialog is currently open, return a [=WebDriver error=] with
[=WebDriver 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 not in the range from 0 to the
number of accounts that the user can choose from in the current flow,
cbiesinger marked this conversation as resolved.
Show resolved Hide resolved
return a [=WebDriver error=] with [=WebDriver 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 [=WebDriver error=] with
[=WebDriver 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. Append an object to |list| with the following properties:
cbiesinger marked this conversation as resolved.
Show resolved Hide resolved
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"`
1. `privacyPolicyUrl` to the {{IdentityProviderClientMetadata/privacy_policy_url}}
if one was provided and the `loginState` is `"SignUp"`

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
[https://github.com/fedidcg/FedCM/blob/main/proposals/context-api.md](context API)
cbiesinger marked this conversation as resolved.
Show resolved Hide resolved
was applied properly

The [=remote end steps=] are:

1. If no FedCM dialog is currently open, return a [=WebDriver error=] with
[=WebDriver error=] [=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|.

## 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
[=WebDriver error=] with [=WebDriver 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 [=WebDriver error=]
with [=WebDriver 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