From a9e7823f59854950ca3acc402e2006271aff6862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Tue, 22 Nov 2022 17:41:55 -0500 Subject: [PATCH 01/17] Queue tasks from in parallel --- spec/index.bs | 151 +++++++++++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 70 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index fa9bf41ee..a33199d4a 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -47,6 +47,7 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ type: dfn text: origin; for: html-origin-def; url: origin.html#concept-origin text: Content-Type Metadata; url: urls-and-fetching.html#content-type + text: DOM manipulation task source; url: webappapis.html#dom-manipulation-task-source type: method text: setTimeout; url: timers-and-user-prompts.html#dom-settimeout @@ -1189,7 +1190,7 @@ requests.
When the {{IdentityCredential}}'s \[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)\ - algorithm is invoked, the user agent MUST execute the following steps: + algorithm is invoked, the user agent MUST execute the following steps (note that these are invoked while [=in parallel=]): 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=map/exists=]. 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=list/size=] is 1. @@ -1202,27 +1203,29 @@ requests. method to return null. If there was no such timer, the developer could easily infer whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=]. 1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0]. - 1. Let |credential| be the result of running the [=potentially create IdentityCredential=] - algorithm with |provider|. + 1. Wait for the |credential| from [=potentially create IdentityCredential=] algorithm with |provider| and |globalObject|. + + Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} + algorithm. See issue. 1. If |credential| is null or [=potentially create IdentityCredential=] threw a {{TypeError}}, wait for the task that throws a {{NetworkError}}, otherwise return |credential|.
-To potentially create IdentityCredential, given an {{IdentityProviderConfig}} |provider|: +To potentially create IdentityCredential, given an {{IdentityProviderConfig}} |provider| and a |globalObject|, execute the following steps: 1. Let |manifest| be the result of running the [=fetch the manifest=] - algorithm with |provider|. + algorithm with |provider| and |globalObject|. 1. If |manifest| is null, return null. 1. Let |accountsList| be the result of running the - [=fetch the accounts list=] algorithm with |manifest| and |provider|. + [=fetch the accounts list=] algorithm with |manifest|, |provider|, and |globalObject|. 1. If |accountsList|'s size is 0, return null. 1. If |accountsList|'s size is 1: 1. Let |account| be |accountsList|[0]. 1. Let |accountState| be the result of running the [=compute account state=] algorithm given |provider| and |account|. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the - [=request permission to sign-up=] algorithm with |account|, |accountState|, |manifest|, and - |provider|. + [=request permission to sign-up=] algorithm with |account|, |accountState|, |manifest|, + |provider|, and |globalObject|. 1. Otherwise, show a dialog to request user permission to sign in via |account|. 1. If the user grants permission, run the [=sign-in=] algorithm with |accountState|. 1. Otherwise: @@ -1232,15 +1235,17 @@ To potentially create IdentityCredential, given an {{IdentityProvider 1. Let |accountState| be the result of running the [=compute account state=] algorithm given |provider| and |account|. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the - [=request permission to sign-up=] algorithm with |account|, |accountState|, |manifest|, and - |provider|. + [=request permission to sign-up=] algorithm with |account|, |accountState|, |manifest|, + |provider|, and |globalObject|. 1. Otherwise, run the [=sign-in=] algorithm with |accountState|. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then return null. 1. Let |token| be the result of running the [=create tokens=] algorithm with |accountState|, - |account|'s {{IdentityProviderAccount/id}}, |provider|, and |manifest|. - 1. Let |credential| be a new {{IdentityCredential}}. - 1. Set |credential|'s {{IdentityCredential/token}} to |token|. - 1. Return |credential|. + |account|'s {{IdentityProviderAccount/id}}, |provider|, |manifest|, and |globalObject|. + 1. Let |credential| be null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to perform the following steps: + 1. Create a new {{IdentityCredential}} given |globalObject|'s realm. + 1. Set |credential|'s {{IdentityCredential/token}} to |token|. + 1. Wait until the above task has been executed, and then return |credential|.
@@ -1259,8 +1264,8 @@ To compute account state given an {{IdentityProviderConfig}} |provide
-To fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest| and an {{IdentityProviderConfig}} - |provider|: +To fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} + |provider| and a |globalObject|: 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. 1. If |accountsUrl| is failure, return an empty list. @@ -1281,14 +1286,15 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |ma 1. Let |accountsList| be a new {{IdentityProviderAccountList}}. Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, |potentialAccountsList|. - 1. Set |accountsList| to |potentialAccountsList|. + 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, |potentialAccountsList|. + 1. Set |accountsList| to |potentialAccountsList|. - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. Return |accountsList|. + Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. + 1. Wait until the processResponseConsumeBody above terminates, and then return |accountsList|. Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336).
@@ -1324,10 +1330,10 @@ To extract the JSON fetch response given a respon
To request permission to sign-up the user with a given {{IdentityProviderAccount}} |account|, an - [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, and an {{IdentityProviderConfig}} - |provider|: + [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} + |provider|, and a |globalObject|: 1. Let |metadata| be the result of running the [=fetch the client metadata=] - algorithm with |manifest| and |provider|. + algorithm with |manifest|, |provider|, and |globalObject|. 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of |account|["{{IdentityProviderAccount/approved_clients}}"], then display the @@ -1345,8 +1351,8 @@ To request permission to sign-up the user with a given {{IdentityProv
-To fetch the client metadata given an {{IdentityProviderAPIConfig}} |manifest| and an - {{IdentityProviderConfig}} |provider|, run the following steps: +To fetch the client metadata given an {{IdentityProviderAPIConfig}} |manifest|, an + {{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps: 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. 1. If |clientMetadataUrl| is failure, return null. @@ -1365,14 +1371,15 @@ To fetch the client metadata given an {{IdentityProviderAPIC 1. Let |clientMetadata| be a new {{IdentityProviderClientMetadata}}. Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, |metadata|. - 1. Copy |metadata| into |clientMetadata|. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. Return |clientMetadata|. + 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, |metadata|. + 1. Copy |metadata| into |clientMetadata|. + + Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. + 1. Wait until the processResponseConsumeBody above terminates, and then return |clientMetadata|.
@@ -1392,7 +1399,8 @@ To sign-in the user with a given an [=AccountState=] |accountState|:
To create tokens given an [=AccountState=] |accountState|, a {{USVString}} |accountId|, - an {{IdentityProviderConfig}} |provider|, and an {{IdentityProviderAPIConfig}} |manifest|: + an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |manifest|, and a + |globalObject|: 1. Assert |accountState|'s {{AccountState/registration state}} is [=registered=]. 1. Assert |accountState|'s {{AccountState/allows logout}} is true. 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider| and @@ -1419,23 +1427,24 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr 1. Let |token| be a new {{IdentityProviderToken}}. Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |fetchedToken|. - 1. Set |token| to |fetchedToken|. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. Return |token|. + 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |fetchedToken|. + 1. Set |token| to |fetchedToken|. + + Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. + 1. Wait until the processResponseConsumeBody above terminates, and then return |token|.
-The fetch the manifest algorithm accepts an {{IdentityProviderConfig}} |provider| and returns an {{IdentityProviderAPIConfig}} object: - 1. In parallel, perform the following two steps: +The fetch the manifest algorithm accepts an {{IdentityProviderConfig}} |provider| and a |globalObject| and returns an {{IdentityProviderAPIConfig}} object: + 1. [=In parallel=], perform the following two steps: 1. Let |manifestInWellKnown| be the result of running [=check the well-known file=], passing - |provider|. + |provider| and |globalObject|. 1. Let |manifest| be the result of running [=fetch the internal manifest=], passing - |provider|. + |provider| and |globalObject|. 1. If |manifestInWellKnown| is true, return |manifest|, otherwise return null.
@@ -1447,7 +1456,7 @@ to keep their actual manifest on an arbitary path while allowing the user agent manipulation to fingerprint. See [[#manifest-fingerprinting]].
-The check the well-known file accepts an {{IdentityProviderConfig}} |provider| and returns +The check the well-known file accepts an {{IdentityProviderConfig}} |provider| and a |globalObject| and returns whether the |provider|'s {{IdentityProviderConfig/configURL}} is included in the [[#idp-api-well-known]] endpoint's {{Well-Known/provider_urls}} list: 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. @@ -1469,21 +1478,22 @@ whether the |provider|'s {{IdentityProviderConfig/configURL}} is included in the 1. [=request/referrer policy=] set to "no-referrer" 1. [=request/credentials mode=] set to "omit" 1. Let |check| be false. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, |discovery|. - 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] is greater than 1, return. - - Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the provider_urls array. - - 1. Set |check| to true if |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] [=string/is=] equal to |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. Return |check|. + 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, |discovery|. + 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] is greater than 1, return. + + Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the provider_urls array. + + 1. Set |check| to true if |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] [=string/is=] equal to |provider|'s + {{IdentityProviderConfig/configURL}}. + 1. Wait until the processResponseConsumeBody above terminates, and then return |check|.
-The fetch the internal manifest algorithm accepts an {{IdentityProviderConfig}} |provider| and returns an {{IdentityProviderAPIConfig}} or null if there is some failure fetching or parsing the manifest: +The fetch the internal manifest algorithm accepts an {{IdentityProviderConfig}} |provider| anda |globalObject| and returns an {{IdentityProviderAPIConfig}} or null if there is some failure fetching or parsing the manifest: 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. If |configUrl| is failure, return null. @@ -1507,14 +1517,15 @@ The fetch the internal manifest algorithm accepts an {{IdentityProvid 1. Let |manifest| be a new {{IdentityProviderAPIConfig}}. Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}}, |fetchedConfig|. - 1. Copy |fetchedConfig| into |manifest|. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. Return |manifest|. + 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}}, |fetchedConfig|. + 1. Copy |fetchedConfig| into |manifest|. + + Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. + 1. Wait until the processResponseConsumeBody above terminates, and then return |manifest|.
From b8a5cea5d36198e1f9f4fe2600d19b3cb9c7313a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Wed, 23 Nov 2022 16:28:53 -0500 Subject: [PATCH 02/17] More --- spec/index.bs | 418 +++++++++++++++++++++++++------------------------- 1 file changed, 208 insertions(+), 210 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index a33199d4a..1f43c9a18 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1203,26 +1203,149 @@ requests. method to return null. If there was no such timer, the developer could easily infer whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=]. 1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0]. - 1. Wait for the |credential| from [=potentially create IdentityCredential=] algorithm with |provider| and |globalObject|. + 1. Run the [=check the well-known file=] algorithm with |provider| and |globalObject|. Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} algorithm. See issue. - 1. If |credential| is null or [=potentially create IdentityCredential=] threw a {{TypeError}}, wait for the task that throws a {{NetworkError}}, otherwise return - |credential|. + 1. Wait until an error is thrown or an {{IdentityCredential}} credential + is returned.
-To potentially create IdentityCredential, given an {{IdentityProviderConfig}} |provider| and a |globalObject|, execute the following steps: - 1. Let |manifest| be the result of running the [=fetch the manifest=] - algorithm with |provider| and |globalObject|. - 1. If |manifest| is null, return null. - 1. Let |accountsList| be the result of running the - [=fetch the accounts list=] algorithm with |manifest|, |provider|, and |globalObject|. - 1. If |accountsList|'s size is 0, return null. +To check the well-known file given an {{IdentityProviderConfig}} |provider| and a +|globalObject|: + 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s + {{IdentityProviderConfig/configURL}}. + 1. If |configUrl| is failure, return false. + 1. Let |rootUrl| be a new [=/URL=]. + 1. Set |rootUrl|'s [=url/scheme=] to |configUrl|'s [=url/scheme=]. + 1. Set |rootUrl|'s [=url/host=] to |configUrl|'s [=url/host=]'s [=host/registrable domain=]. + 1. Set |rootUrl|'s [=url/path=] to the list «".well-known", "web-identity"». + 1. If |rootUrl| is not a [=potentially trustworthy URL=], return false. + 1. Let |request| be a new request with the following properties: + 1. [=request/url=] set to |rootUrl| + 1. [=request/client=] set to null + 1. [=request/window=] set to "no-window" + 1. [=request/service-workers mode=] set to "none" + 1. [=request/destination=] set to "webidentity" + 1. [=request/origin=] set to a unique [=opaque origin=] + 1. [=request/header list=] set to a [=list=] containing a single [=header=] with + [=header/name=] set to `Accept` and [=header/value=] set to `application/json` + 1. [=request/referrer policy=] set to "no-referrer" + 1. [=request/credentials mode=] set to "omit" + 1. Let |check| be false. + 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the + following steps: + 1. [=Fetch=] |request| with processResponseConsumeBody set to the + following steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, + |discovery|. + 1. Let |check| be set as follows: + 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] + is greater than 1, set |check| to false. + + Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the provider_urls array. + + 1. Otherwise, set |check| to true if |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] + [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. + 1. Run [=on well-known check completed=], passing |check|, |provider|, and |globalObject|. +
+ +
+On well-known check completed, given a boolean |check|, an {{IdentityProviderConfig}} +|provider| and a |globalObject|: + 1. If |check| is false, throw a "{{NetworkError}}" {{DOMException}}. + 1. Run [=fetch the internal manifest=], passing |provider| and |globalObject|. +
+ +NOTE: The well-known file and internal manifest fetches could be performed simultaneously, it is +just simpler to specify these as happening one after the other. + +
+To fetch the internal manifest algorithm given an {{IdentityProviderConfig}} |provider| +and a |globalObject|: + 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s + {{IdentityProviderConfig/configURL}}. + 1. If |configUrl| is failure, return null. + 1. Run a [[!CSP]] check with a [[CSP#directive-connect-src|connect-src]] + directive on the URL passed as |configUrl|. + 1. If |configUrl| is not a [=potentially trustworthy URL=], return null. + 1. Let |request| be a new request with the following properties: + 1. [=request/url=] set to |configUrl| + 1. [=request/redirect mode=] set to "error" + 1. [=request/client=] set to null + 1. [=request/window=] set to "no-window" + 1. [=request/service-workers mode=] set to "none" + 1. [=request/destination=] set to "webidentity" + 1. [=request/origin=] set to a unique [=opaque origin=] + 1. [=request/header list=] set to a [=list=] containing a single [=header=] with + [=header/name=] set to `Accept` and [=header/value=] set to `application/json` + 1. [=request/referrer policy=] set to "no-referrer" + 1. [=request/credentials mode=] set to "omit" + 1. Let |request| be a new request whose [=request/url=] is |configUrl| and + [=request/redirect mode=] set to "error". + 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the + following steps: + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}}, |manifest|. + 1. Run [=on internal manifest fetched=], passing |manifest|, provider|, and |globalObject|. +
+ +NOTE: We use a two-tier manifest list in order to prevent the [=IDP=] to easily determine the [=RP=] +that a user is visiting by encoding the information in the manifest path. We solve this issue by +requiring a manifest list to be on the root of the [=IDP=]. The manifest itself can be anywhere, but +it will not be used if the user agent does not find it in the manifest list. This allows the [=IDP=] +to keep their actual manifest on an arbitary path while allowing the user agent to prevent manifest +manipulation to fingerprint. See [[#manifest-fingerprinting]]. + +
+On internal manifest fetched, given an {{IdentityProviderAPIConfig}} |manifest|, an +{{IdentityProviderConfig}} |provider| and a |globalObject|: + 1. If |manifest| is null, throw a "{{NetworkError}}" {{DOMException}}. + 1. Run the [=fetch the accounts list=] algorithm with |manifest|, |provider|, and |globalObject|. +
+ +
+To fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest|, an +{{IdentityProviderConfig}} |provider| and a |globalObject|: + 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider| and + |manifest|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. + 1. If |accountsUrl| is failure, return an empty list. + 1. Let |request| be a new request with the following properties: + 1. [=request/url=] set to |accountsUrl| + 1. [=request/redirect mode=] set to "error" + 1. [=request/client=] set to null + 1. [=request/window=] set to "no-window" + 1. [=request/service-workers mode=] set to "none" + 1. [=request/destination=] set to "webidentity" + 1. [=request/origin=] set to a unique [=opaque origin=] + 1. [=request/header list=] set to a [=list=] containing a single [=header=] with + [=header/name=] set to `Accept` and [=header/value=] set to `application/json` + 1. [=request/referrer policy=] set to "no-referrer" + 1. [=request/credentials mode=] set to "include" + + Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). + 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, |accountsList|. + 1. Run [=on accounts list fetched=], passing |accountsList|, |manifest|, |provider|, and |globalObject|. + + Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336). +
+ +
+On accounts list fetched, given an {{IdentityProviderAccountList}} |accountsList|, an +{{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} |provider| and a +|globalObject|, run the following steps [=in parallel=]: 1. If |accountsList|'s size is 1: 1. Let |account| be |accountsList|[0]. 1. Let |accountState| be the result of running the [=compute account state=] algorithm - given |provider| and |account|. + given |provider|, |account|, and |globalObject|. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the [=request permission to sign-up=] algorithm with |account|, |accountState|, |manifest|, |provider|, and |globalObject|. @@ -1238,39 +1361,29 @@ To potentially create IdentityCredential, given an {{IdentityProvider [=request permission to sign-up=] algorithm with |account|, |accountState|, |manifest|, |provider|, and |globalObject|. 1. Otherwise, run the [=sign-in=] algorithm with |accountState|. - 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then return null. - 1. Let |token| be the result of running the [=create tokens=] algorithm with |accountState|, - |account|'s {{IdentityProviderAccount/id}}, |provider|, |manifest|, and |globalObject|. - 1. Let |credential| be null. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to perform the following steps: - 1. Create a new {{IdentityCredential}} given |globalObject|'s realm. - 1. Set |credential|'s {{IdentityCredential/token}} to |token|. - 1. Wait until the above task has been executed, and then return |credential|. -
- -
-To compute account state given an {{IdentityProviderConfig}} |provider| and an - {{IdentityProviderAccount}} |account|, run the following steps: - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. Let |idpOrigin| be the [=origin=] corresponding to |configUrl|. - 1. Let |rpOrigin| be [=this=]'s [=Document/origin=]. - 1. Let |accountId| be |account|'s {{IdentityProviderAccount/id}}. - 1. Let |triple| be (|rpOrigin|, |idpOrigin|, |accountId|). - 1. If [=state machine map=][|triple|] does not exist, set [=state machine map=][|triple|] to a - new [=AccountState=]. - 1. Let |accountState| be [=state machine map=][|triple|]. - 1. Return |accountState|. + 1. Wait until the user agent's dialog is closed and |accountState| has been updated. + 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new + "{{AbortError}}" {{DOMException}}. + 1. Run the [=create tokens=] algorithm with |accountState|, |account|'s + {{IdentityProviderAccount/id}}, |provider|, |manifest|, and |globalObject|.
-To fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} - |provider| and a |globalObject|: - 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider| and - |manifest|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. - 1. If |accountsUrl| is failure, return an empty list. +To create tokens given an [=AccountState=] |accountState|, a {{USVString}} |accountId|, + an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |manifest|, and a + |globalObject|: + 1. Assert |accountState|'s {{AccountState/registration state}} is [=registered=]. + 1. Assert |accountState|'s {{AccountState/allows logout}} is true. + 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider| and + |manifest|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"]. + 1. If |idTokenUrl| is failure, return null. + 1. Let |requestBody| be a [=string=] resulting in concatenating "client_id=", + |provider|'s {{IdentityProviderConfig/clientId}}, "&nonce=", + |provider|'s {{IdentityProviderConfig/nonce}}, "&account_id=", and |accountId|. 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |accountsUrl| + 1. [=request/url=] set to |idTokenUrl| + 1. [=request/mode=] set to "POST" + 1. [=request/body=] set to the [=UTF-8 encode=] of |requestBody| 1. [=request/redirect mode=] set to "error" 1. [=request/client=] set to null 1. [=request/window=] set to "no-window" @@ -1278,25 +1391,40 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |ma 1. [=request/destination=] set to "webidentity" 1. [=request/origin=] set to a unique [=opaque origin=] 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to `application/json` - 1. [=request/referrer policy=] set to "no-referrer" + [=header/name=] set to `Accept` and [=header/value=] set to + `application/x-www-form-urlencoded` + 1. [=request/referrer=] set to [=RP=]'s URL (TODO). 1. [=request/credentials mode=] set to "include" - - Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). - 1. Let |accountsList| be a new {{IdentityProviderAccountList}}. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, |potentialAccountsList|. - 1. Set |accountsList| to |potentialAccountsList|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |token|. + 1. Run [=on token created=] given |token| and |globalObject|. +
- Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. Wait until the processResponseConsumeBody above terminates, and then return |accountsList|. +
+On token created, given an {{IdentityProviderToken}} |token| and a |globalObject|: + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to perform the following steps: + 1. Create a new {{IdentityCredential}} given |globalObject|'s realm. + 1. Set |credential|'s {{IdentityCredential/token}} to |token|. + 1. [=In parallel=], pass |credential| to the {{Credential/[[DiscoverFromExternalSource]]}} + callback. +
- Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336). +
+To compute account state given an {{IdentityProviderConfig}} |provider|, an + {{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps: + 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s + {{IdentityProviderConfig/configURL}}. + 1. Let |idpOrigin| be the [=origin=] corresponding to |configUrl|. + 1. Let |rpOrigin| be |globalObject|'s [=associated Document=]'s [=Document/origin=]. + 1. Let |accountId| be |account|'s {{IdentityProviderAccount/id}}. + 1. Let |triple| be (|rpOrigin|, |idpOrigin|, |accountId|). + 1. If [=state machine map=][|triple|] does not exist, set [=state machine map=][|triple|] to a + new [=AccountState=]. + 1. Let |accountState| be [=state machine map=][|triple|]. + 1. Return |accountState|.
@@ -1329,29 +1457,16 @@ To extract the JSON fetch response given a respon
-To request permission to sign-up the user with a given {{IdentityProviderAccount}} |account|, an +To request permission to sign-up the user with a given an {{IdentityProviderAccount}} |account|, an [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} |provider|, and a |globalObject|: - 1. Let |metadata| be the result of running the [=fetch the client metadata=] - algorithm with |manifest|, |provider|, and |globalObject|. - 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s - {{IdentityProviderConfig/clientId}} is not in the list of - |account|["{{IdentityProviderAccount/approved_clients}}"], then display the - |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] link. - 1. If |metadata| is not null, |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] is defined, - and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of - |account|["{{IdentityProviderAccount/approved_clients}}"], then display the - |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] link. - 1. Prompt the user to gather explicit intent to create an account. The user agent MAY use the - {{IdentityProviderBranding}} to inform the style choices of its UI. - 1. If the user does not grants permission, return. - 1. Change |accountState|'s {{AccountState/registration state}} from [=unregistered=] to - [=registered=]. - 1. Change |accountState|'s {{AccountState/allows logout}} from false to true. + 1. Run the [=fetch the client metadata=] algorithm with |account|, |accountState|, |manifest|, + |provider|, and |globalObject|.
-To fetch the client metadata given an {{IdentityProviderAPIConfig}} |manifest|, an +To fetch the client metadata given {{IdentityProviderAccount}} |account|, an + [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps: 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. @@ -1368,18 +1483,32 @@ To fetch the client metadata given an {{IdentityProviderAPIC [=header/name=] set to `Accept` and [=header/value=] set to `application/json` 1. [=request/referrer=] set to [=RP=]'s URL (TODO). 1. [=request/credentials mode=] set to "omit" - 1. Let |clientMetadata| be a new {{IdentityProviderClientMetadata}}. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, |metadata|. - 1. Copy |metadata| into |clientMetadata|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, |clientMetadata|. + 1. Run [=on client metadata fetched=], passing |account|, |accountState|, |clientMetadata|, and |provider|. +
- Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. Wait until the processResponseConsumeBody above terminates, and then return |clientMetadata|. +
+On client metadata fetched, given an {{IdentityProviderAccount}} |account|, an + [=AccountState=] |accountState|, {{IdentityProviderClientMetadata}} |metadata|, and an + {{IdentityProviderConfig}} |provider|, run the following steps [=in parallel=]: + 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s + {{IdentityProviderConfig/clientId}} is not in the list of + |account|["{{IdentityProviderAccount/approved_clients}}"], then display the + |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] link. + 1. If |metadata| is not null, |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] is defined, + and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of + |account|["{{IdentityProviderAccount/approved_clients}}"], then display the + |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] link. + 1. Prompt the user to gather explicit intent to create an account. The user agent MAY use the + {{IdentityProviderBranding}} to inform the style choices of its UI. + 1. If the user does not grants permission, return. + 1. Change |accountState|'s {{AccountState/registration state}} from [=unregistered=] to + [=registered=]. + 1. Change |accountState|'s {{AccountState/allows logout}} from false to true.
@@ -1397,137 +1526,6 @@ To sign-in the user with a given an [=AccountState=] |accountState|: 1. Change |accountState|'s {{AccountState/allows logout}} from false to true.
-
-To create tokens given an [=AccountState=] |accountState|, a {{USVString}} |accountId|, - an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |manifest|, and a - |globalObject|: - 1. Assert |accountState|'s {{AccountState/registration state}} is [=registered=]. - 1. Assert |accountState|'s {{AccountState/allows logout}} is true. - 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider| and - |manifest|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"]. - 1. If |idTokenUrl| is failure, return null. - 1. Let |requestBody| be a [=string=] resulting in concatenating "client_id=", - |provider|'s {{IdentityProviderConfig/clientId}}, "&nonce=", - |provider|'s {{IdentityProviderConfig/nonce}}, "&account_id=", and |accountId|. - 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |idTokenUrl| - 1. [=request/mode=] set to "POST" - 1. [=request/body=] set to the [=UTF-8 encode=] of |requestBody| - 1. [=request/redirect mode=] set to "error" - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to - `application/x-www-form-urlencoded` - 1. [=request/referrer=] set to [=RP=]'s URL (TODO). - 1. [=request/credentials mode=] set to "include" - 1. Let |token| be a new {{IdentityProviderToken}}. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |fetchedToken|. - 1. Set |token| to |fetchedToken|. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. Wait until the processResponseConsumeBody above terminates, and then return |token|. -
- -
-The fetch the manifest algorithm accepts an {{IdentityProviderConfig}} |provider| and a |globalObject| and returns an {{IdentityProviderAPIConfig}} object: - 1. [=In parallel=], perform the following two steps: - 1. Let |manifestInWellKnown| be the result of running [=check the well-known file=], passing - |provider| and |globalObject|. - 1. Let |manifest| be the result of running [=fetch the internal manifest=], passing - |provider| and |globalObject|. - 1. If |manifestInWellKnown| is true, return |manifest|, otherwise return null. -
- -NOTE: We use a two-tier manifest list in order to prevent the [=IDP=] to easily determine the [=RP=] -that a user is visiting by encoding the information in the manifest path. We solve this issue by -requiring a manifest list to be on the root of the [=IDP=]. The manifest itself can be anywhere, but -it will not be used if the user agent does not find it in the manifest list. This allows the [=IDP=] -to keep their actual manifest on an arbitary path while allowing the user agent to prevent manifest -manipulation to fingerprint. See [[#manifest-fingerprinting]]. - -
-The check the well-known file accepts an {{IdentityProviderConfig}} |provider| and a |globalObject| and returns -whether the |provider|'s {{IdentityProviderConfig/configURL}} is included in the [[#idp-api-well-known]] endpoint's {{Well-Known/provider_urls}} list: - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. If |configUrl| is failure, return false. - 1. Let |rootUrl| be a new [=/URL=]. - 1. Set |rootUrl|'s [=url/scheme=] to |configUrl|'s [=url/scheme=]. - 1. Set |rootUrl|'s [=url/host=] to |configUrl|'s [=url/host=]'s [=host/registrable domain=]. - 1. Set |rootUrl|'s [=url/path=] to the list «".well-known", "web-identity"». - 1. If |rootUrl| is not a [=potentially trustworthy URL=], return false. - 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |rootUrl| - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to `application/json` - 1. [=request/referrer policy=] set to "no-referrer" - 1. [=request/credentials mode=] set to "omit" - 1. Let |check| be false. - 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, |discovery|. - 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] is greater than 1, return. - - Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the provider_urls array. - - 1. Set |check| to true if |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] [=string/is=] equal to |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. Wait until the processResponseConsumeBody above terminates, and then return |check|. -
- -
-The fetch the internal manifest algorithm accepts an {{IdentityProviderConfig}} |provider| anda |globalObject| and returns an {{IdentityProviderAPIConfig}} or null if there is some failure fetching or parsing the manifest: - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. If |configUrl| is failure, return null. - 1. Run a [[!CSP]] check with a [[CSP#directive-connect-src|connect-src]] - directive on the URL passed as |configUrl|. - 1. If |configUrl| is not a [=potentially trustworthy URL=], return null. - 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |configUrl| - 1. [=request/redirect mode=] set to "error" - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to `application/json` - 1. [=request/referrer policy=] set to "no-referrer" - 1. [=request/credentials mode=] set to "omit" - 1. Let |request| be a new request whose [=request/url=] is |configUrl| and - [=request/redirect mode=] set to "error". - 1. Let |manifest| be a new {{IdentityProviderAPIConfig}}. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}}, |fetchedConfig|. - 1. Copy |fetchedConfig| into |manifest|. - - Note: This operation is not defined but should be removed when we [integrate](https://github.com/fedidcg/FedCM/issues/261) with Fetch. - 1. Wait until the processResponseConsumeBody above terminates, and then return |manifest|. -
- ### IDP Sign-out ### {#browser-api-idp-sign-out} @@ -1876,7 +1874,7 @@ these scenarios consider how user tracking might happen **without** them. See al ### Manifest Fingerprinting ### {#manifest-fingerprinting} -Suppose that the FedCM API did not have a two-tier manifest (see the [=fetch the manifest=] +Suppose that the FedCM API did not have a two-tier manifest (see the [=on well-known check completed=] algorithm), and instead directly had a single manifest. This would introduce the following fingerprinting attack: @@ -2127,7 +2125,7 @@ IDPs are also offered an extension to the {{IdentityProviderAPIConfig}} object t :: A URL that allows a user to sign-in to the [=IDP=]. -The [=user agent=] uses the following [=maybe fetch the accounts list=] in the [=potentially create IdentityCredential=] algorithm, as opposed to the [=fetch the accounts list=] algorithm. It would also return early on the [=potentially create IdentityCredential=] algorithm if the user was {{Sign-in Status/signed-out}}. +The [=user agent=] uses the following [=maybe fetch the accounts list=] instead of the [=fetch the accounts list=] algorithm. It would also return early on if the user was {{Sign-in Status/signed-out}}.
To maybe fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest| and an {{IdentityProviderConfig}} From e18539f341058c352267520cf929c15d7751974b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Wed, 14 Dec 2022 11:12:01 -0500 Subject: [PATCH 03/17] Feedback --- spec/index.bs | 266 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 178 insertions(+), 88 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 1f43c9a18..58a230919 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1222,34 +1222,51 @@ To check the well-known file given an {{IdentityProviderConfig}} |pro 1. Set |rootUrl|'s [=url/host=] to |configUrl|'s [=url/host=]'s [=host/registrable domain=]. 1. Set |rootUrl|'s [=url/path=] to the list «".well-known", "web-identity"». 1. If |rootUrl| is not a [=potentially trustworthy URL=], return false. - 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |rootUrl| - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to `application/json` - 1. [=request/referrer policy=] set to "no-referrer" - 1. [=request/credentials mode=] set to "omit" + 1. Let |request| be a new request as follows: + + : [=request/URL=] + :: |rootUrl| + : [=request/client=] + :: null + : [=request/window=] + :: "no-window" + : [=request/service-workers mode=] + :: "none" + : [=request/destination=] + :: "webidentity" + : [=request/origin=] + :: a unique [=opaque origin=] + : [=request/header list=] + :: a [=list=] containing a single [=header=] with [=header/name=] set to `Accept` and + [=header/value=] set to `application/json` + : [=request/referrer policy=] + :: "no-referrer" + : [=request/credentials mode=] + :: "omit" + + Note: The spec is yet to be updated so that this request is created with + [=request/mode=] set to "unsafe-no-cors". See the relevant + [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. Let |check| be false. 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, - |discovery|. - 1. Let |check| be set as follows: - 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] - is greater than 1, set |check| to false. - - Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the provider_urls array. - - 1. Otherwise, set |check| to true if |discovery|["{{IdentityProviderWellKnown/provider_urls}}""] - [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. - 1. Run [=on well-known check completed=], passing |check|, |provider|, and |globalObject|. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| + to perform the following steps: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, + |discovery|. + 1. Let |check| be set as follows: + 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] + is greater than 1, set |check| to false. + + Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the + provider_urls array. + + 1. Otherwise, set |check| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] + [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. + 1. Run [=on well-known check completed=], passing |check|, |provider|, and |globalObject|.
@@ -1271,20 +1288,33 @@ and a |globalObject|: 1. Run a [[!CSP]] check with a [[CSP#directive-connect-src|connect-src]] directive on the URL passed as |configUrl|. 1. If |configUrl| is not a [=potentially trustworthy URL=], return null. - 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |configUrl| - 1. [=request/redirect mode=] set to "error" - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to `application/json` - 1. [=request/referrer policy=] set to "no-referrer" - 1. [=request/credentials mode=] set to "omit" - 1. Let |request| be a new request whose [=request/url=] is |configUrl| and - [=request/redirect mode=] set to "error". + 1. Let |request| be a new request as follows: + + : [=request/url=] + :: |configUrl| + : [=request/redirect mode=] + :: "error" + : [=request/client=] + :: null + : [=request/window=] + :: "no-window" + : [=request/service-workers mode=] + :: "none" + : [=request/destination=] + :: "webidentity" + : [=request/origin=] + :: a unique [=opaque origin=] + : [=request/header list=] + :: a [=list=] containing a single [=header=] with [=header/name=] set to `Accept` and + [=header/value=] set to `application/json` + : [=request/referrer policy=] + :: "no-referrer" + : [=request/credentials mode=] + :: "omit" + + Note: The spec is yet to be updated so that this request is created with + [=request/mode=] set to "unsafe-no-cors". See the relevant + [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: 1. [=Fetch=] |request| with processResponseConsumeBody set to the following @@ -1314,20 +1344,35 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |ma 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. 1. If |accountsUrl| is failure, return an empty list. - 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |accountsUrl| - 1. [=request/redirect mode=] set to "error" - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to `application/json` - 1. [=request/referrer policy=] set to "no-referrer" - 1. [=request/credentials mode=] set to "include" - - Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). + 1. Let |request| be a new request as follows: + + : [=request/url=] + :: |accountsUrl| + : [=request/redirect mode=] + :: "error" + : [=request/client=] + :: null + : [=request/window=] + :: "no-window" + : [=request/service-workers mode=] + :: "none" + : [=request/destination=] + :: "webidentity" + : [=request/origin=] + :: a unique [=opaque origin=] + : [=request/header list=] + :: a [=list=] containing a single [=header=] with [=header/name=] set to `Accept` and + [=header/value=] set to `application/json` + : [=request/referrer policy=] + :: "no-referrer" + : [=request/credentials mode=] + :: "include" + + Note: The spec is yet to be updated so that this request is created with + [=request/mode=] set to "unsafe-no-cors". See the relevant + [pull request](https://github.com/whatwg/fetch/pull/1533) for details. + + Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: @@ -1380,21 +1425,37 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr 1. Let |requestBody| be a [=string=] resulting in concatenating "client_id=", |provider|'s {{IdentityProviderConfig/clientId}}, "&nonce=", |provider|'s {{IdentityProviderConfig/nonce}}, "&account_id=", and |accountId|. - 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |idTokenUrl| - 1. [=request/mode=] set to "POST" - 1. [=request/body=] set to the [=UTF-8 encode=] of |requestBody| - 1. [=request/redirect mode=] set to "error" - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to - `application/x-www-form-urlencoded` - 1. [=request/referrer=] set to [=RP=]'s URL (TODO). - 1. [=request/credentials mode=] set to "include" + 1. Let |request| be a new request as follows: + + : [=request/url=] + :: |idTokenUrl| + : [=request/mode=] + :: "POST" + : [=request/body=] + :: the [=UTF-8 encode=] of |requestBody| + : [=request/redirect mode=] + :: "error" + : [=request/client=] + :: null + : [=request/window=] + :: "no-window" + : [=request/service-workers mode=] + :: "none" + : [=request/destination=] + :: "webidentity" + : [=request/origin=] + :: a unique [=opaque origin=] + : [=request/header list=] + :: a [=list=] containing a single [=header=] with [=header/name=] set to `Accept` and + [=header/value=] set to `application/x-www-form-urlencoded` + : [=request/referrer=] + :: [=RP=]'s URL (TODO). + : [=request/credentials mode=] + :: "include" + + Note: The spec is yet to be updated so that this request is created with + [=request/mode=] set to "unsafe-no-cors". See the relevant + [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: @@ -1471,18 +1532,33 @@ To fetch the client metadata given {{IdentityProviderAccount 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. 1. If |clientMetadataUrl| is failure, return null. - 1. Let |request| be a new request with the following properties: - 1. [=request/url=] set to |clientMetadataUrl| - 1. [=request/redirect mode=] set to "error" - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/header list=] set to a [=list=] containing a single [=header=] with - [=header/name=] set to `Accept` and [=header/value=] set to `application/json` - 1. [=request/referrer=] set to [=RP=]'s URL (TODO). - 1. [=request/credentials mode=] set to "omit" + 1. Let |request| be a new request as follows: + + : [=request/url=] + :: |clientMetadataUrl| + : [=request/redirect mode=] + :: "error" + : [=request/client=] + :: null + : [=request/window=] + :: "no-window" + : [=request/service-workers mode=] + :: "none" + : [=request/destination=] + :: "webidentity" + : [=request/origin=] + :: a unique [=opaque origin=] + : [=request/header list=] + :: a [=list=] containing a single [=header=] with [=header/name=] set to `Accept` and + [=header/value=] set to `application/json` + : [=request/referrer=] + :: [=RP=]'s URL (TODO). + : [=request/credentials mode=] + :: "omit" + + Note: The spec is yet to be updated so that this request is created with + [=request/mode=] set to "unsafe-no-cors". See the relevant + [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: @@ -1621,16 +1697,30 @@ steps: 1. Let |accountState| be [=state machine map=][|triple|]. 1. If the |accountState|'s {{AccountState/registration state}} is [=unregistered=] or |accountState|'s {{AccountState/allows logout}} is false, continue. - 1. Let |fetchRequest| be a new request with the following properties: - 1. [=request/url=] set to |request|'s {{IdentityCredentialLogoutRPsRequest/url}} - 1. [=request/mode=] set to "GET" - 1. [=request/redirect mode=] set to "error" - 1. [=request/client=] set to null - 1. [=request/window=] set to "no-window" - 1. [=request/service-workers mode=] set to "none" - 1. [=request/destination=] set to "webidentity" - 1. [=request/origin=] set to a unique [=opaque origin=] - 1. [=request/credentials mode=] set to "include" + 1. Let |fetchRequest| be a new request as follows: + + : [=request/url=] + :: |request|'s {{IdentityCredentialLogoutRPsRequest/url}} + : [=request/mode=] + :: "GET" + : [=request/redirect mode=] + :: "error" + : [=request/client=] + :: null + : [=request/window=] + :: "no-window" + : [=request/service-workers mode=] + :: "none" + : [=request/destination=] + :: "webidentity" + : [=request/origin=] + :: a unique [=opaque origin=] + : [=request/credentials mode=] + :: "include" + + Note: The spec is yet to be updated so that this request is created + with [=request/mode=] set to "unsafe-no-cors". See the relevant + [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. [=Fetch=] |fetchRequest|. 1. Set the |accountState| {{AccountState/allows logout}} to false. 1. Resolve |promise| with [undefined] and return |promise|. From e05d5ab0ec6fe74352d670242cfd1723c057a8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Thu, 15 Dec 2022 16:35:46 -0500 Subject: [PATCH 04/17] feedback --- spec/index.bs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 58a230919..1e4a5452d 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -21,6 +21,7 @@ Abstract: A Web Platform API that allows users to login to websites with their f Test Suite: https://github.com/web-platform-tests/wpt/blob/master/credential-management/ +
 spec: ecma262; urlPrefix: https://tc39.github.io/ecma262/
     type: dfn
@@ -1244,8 +1245,8 @@ To check the well-known file given an {{IdentityProviderConfig}} |pro
         :  [=request/credentials mode=]
         :: "omit"
     
-    Note: The spec is yet to be updated so that this request is created with
-    [=request/mode=] set to "unsafe-no-cors". See the relevant
+    Note: The spec is yet to be updated so that all requests are created
+    with [=request/mode=] set to "unsafe-no-cors". See the relevant
     [pull request](https://github.com/whatwg/fetch/pull/1533) for details.
     1. Let |check| be false.
     1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the
@@ -1312,9 +1313,6 @@ and a |globalObject|:
         :  [=request/credentials mode=]
         :: "omit"
 
-    Note: The spec is yet to be updated so that this request is created with
-    [=request/mode=] set to "unsafe-no-cors". See the relevant
-    [pull request](https://github.com/whatwg/fetch/pull/1533) for details.
     1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the
         following steps:
         1. [=Fetch=] |request| with processResponseConsumeBody set to the following
@@ -1368,10 +1366,6 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |ma
         :  [=request/credentials mode=]
         :: "include"
 
-    Note: The spec is yet to be updated so that this request is created with
-    [=request/mode=] set to "unsafe-no-cors". See the relevant
-    [pull request](https://github.com/whatwg/fetch/pull/1533) for details.
-
     Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953).
     1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps:
         1. [=Fetch=] |request| with processResponseConsumeBody set to the following
@@ -1453,9 +1447,6 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr
         :  [=request/credentials mode=]
         :: "include"
 
-    Note: The spec is yet to be updated so that this request is created with
-    [=request/mode=] set to "unsafe-no-cors". See the relevant
-    [pull request](https://github.com/whatwg/fetch/pull/1533) for details.
     1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps:
         1. [=Fetch=] |request| with processResponseConsumeBody set to the following
             steps given a response |response|:
@@ -1556,9 +1547,6 @@ To fetch the client metadata given {{IdentityProviderAccount
         :  [=request/credentials mode=]
         :: "omit"
 
-    Note: The spec is yet to be updated so that this request is created with
-    [=request/mode=] set to "unsafe-no-cors". See the relevant
-    [pull request](https://github.com/whatwg/fetch/pull/1533) for details.
     1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps:
         1. [=Fetch=] |request| with processResponseConsumeBody set to the following
             steps given a response |response|:
@@ -1718,9 +1706,6 @@ steps:
             :  [=request/credentials mode=]
             :: "include"
 
-        Note: The spec is yet to be updated so that this request is created
-        with [=request/mode=] set to "unsafe-no-cors". See the relevant
-        [pull request](https://github.com/whatwg/fetch/pull/1533) for details.
         1. [=Fetch=] |fetchRequest|.
         1. Set the |accountState| {{AccountState/allows logout}} to false.
     1. Resolve |promise| with [undefined] and return |promise|.

From c47a2e55cdfd24c02b1a8a14b3751d0c5854a252 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= 
Date: Wed, 4 Jan 2023 12:48:32 -0800
Subject: [PATCH 05/17] b

---
 spec/index.bs | 87 +++++++++++++++++++++++++++++----------------------
 1 file changed, 49 insertions(+), 38 deletions(-)

diff --git a/spec/index.bs b/spec/index.bs
index 1e4a5452d..0cd4f78a7 100644
--- a/spec/index.bs
+++ b/spec/index.bs
@@ -1189,22 +1189,28 @@ The {{CredentialRequestOptions/signal}} is used as an abort signal for the
 requests.
 
 
- When the {{IdentityCredential}}'s - \[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)\ - algorithm is invoked, the user agent MUST execute the following steps (note that these are invoked while [=in parallel=]): +When the {{IdentityCredential}}'s +\[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) +algorithm is invoked, the user agent MUST execute the following steps (note that these are invoked while [=in parallel=]). +This returns an {{IdentityCredential}}, null, or an error. + 1. Assert: These steps are running [=in parallel=]. 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=map/exists=]. 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=list/size=] is 1. Issue: Support choosing accounts from multiple [=Identity Provider=]s, as described [here](https://github.com/fedidcg/FedCM/issues/319). 1. Run {{setTimeout}} passing a [=task=] which throws a {{NetworkError}}, after a timeout of 60 seconds. + + Issue: Do not use {{setTimeout}} directly, as that is not correct. See the relevant + [issue](https://github.com/fedidcg/FedCM/issues/389). Note: the purpose of having a timer here is to avoid leaking the reason causing this method to return null. If there was no such timer, the developer could easily infer whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=]. 1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0]. - 1. Run the [=check the well-known file=] algorithm with |provider| and |globalObject|. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] to + [=check the well-known file=] algorithm with |provider| and |globalObject|. Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} algorithm. See issue. @@ -1214,7 +1220,8 @@ requests.
To check the well-known file given an {{IdentityProviderConfig}} |provider| and a -|globalObject|: +|globalObject|, run the following steps: + 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. If |configUrl| is failure, return false. @@ -1248,6 +1255,7 @@ To check the well-known file given an {{IdentityProviderConfig}} |pro Note: The spec is yet to be updated so that all requests are created with [=request/mode=] set to "unsafe-no-cors". See the relevant [pull request](https://github.com/whatwg/fetch/pull/1533) for details. + 1. Let |check| be false. 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: @@ -1283,6 +1291,7 @@ just simpler to specify these as happening one after the other.
To fetch the internal manifest algorithm given an {{IdentityProviderConfig}} |provider| and a |globalObject|: + 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. If |configUrl| is failure, return null. @@ -1313,13 +1322,11 @@ and a |globalObject|: : [=request/credentials mode=] :: "omit" - 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the - following steps: - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}}, |manifest|. - 1. Run [=on internal manifest fetched=], passing |manifest|, provider|, and |globalObject|. + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}}, |manifest|. + 1. Run [=on internal manifest fetched=], passing |manifest|, provider|, and |globalObject|.
NOTE: We use a two-tier manifest list in order to prevent the [=IDP=] to easily determine the [=RP=] @@ -1367,14 +1374,14 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |ma :: "include" Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). - 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, |accountsList|. - 1. Run [=on accounts list fetched=], passing |accountsList|, |manifest|, |provider|, and |globalObject|. - Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336). + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, |accountsList|. + 1. Run [=on accounts list fetched=], passing |accountsList|, |manifest|, |provider|, and |globalObject|. + + Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336).
@@ -1457,16 +1464,16 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr
On token created, given an {{IdentityProviderToken}} |token| and a |globalObject|: - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to perform the following steps: - 1. Create a new {{IdentityCredential}} given |globalObject|'s realm. - 1. Set |credential|'s {{IdentityCredential/token}} to |token|. - 1. [=In parallel=], pass |credential| to the {{Credential/[[DiscoverFromExternalSource]]}} - callback. + 1. Create a new {{IdentityCredential}} given |globalObject|'s realm. + 1. Set |credential|'s {{IdentityCredential/token}} to |token|. + 1. [=In parallel=], pass |credential| to the {{Credential/[[DiscoverFromExternalSource]]}} + callback.
To compute account state given an {{IdentityProviderConfig}} |provider|, an - {{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps: +{{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps. This returns +an [=AccountState=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. Let |idpOrigin| be the [=origin=] corresponding to |configUrl|. @@ -1481,7 +1488,8 @@ To compute account state given an {{IdentityProviderConfig}} |provide
When computing the manifest URL given an {{IdentityProviderConfig}} |provider| and a -[=string=] |manifestString|, perform the following steps: +[=string=] |manifestString|, perform the following steps. This returns a URL or +failure. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. Let |manifestUrl| be the result of running [=url parser=] given |manifestString|. @@ -1493,10 +1501,12 @@ When computing the manifest URL given an {{IdentityProviderConfig}} | 1. If |manifestUrl| is failure, return failure. 1. If |manifestUrl| is not [=same origin=] with |configUrl|, return failure. 1. If |manifestUrl| is not a [=potentially trustworthy URL=], return failure. + 1. Return |manifestUrl|.
-To extract the JSON fetch response given a response |response|: +To extract the JSON fetch response given a response |response|, +run the following steps. This returns an [=ordered map=] or null. 1. If |response| is a [=network error=] or its [=response/status=] is not an [=ok status=], return null. 1. Let |mimeType| be the result of extracting a MIME TYPE from |response|'s @@ -1510,16 +1520,16 @@ To extract the JSON fetch response given a respon
To request permission to sign-up the user with a given an {{IdentityProviderAccount}} |account|, an - [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} - |provider|, and a |globalObject|: +[=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} +|provider|, and a |globalObject|: 1. Run the [=fetch the client metadata=] algorithm with |account|, |accountState|, |manifest|, |provider|, and |globalObject|.
To fetch the client metadata given {{IdentityProviderAccount}} |account|, an - [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an - {{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps: +[=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an +{{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps: 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. 1. If |clientMetadataUrl| is failure, return null. @@ -1557,8 +1567,8 @@ To fetch the client metadata given {{IdentityProviderAccount
On client metadata fetched, given an {{IdentityProviderAccount}} |account|, an - [=AccountState=] |accountState|, {{IdentityProviderClientMetadata}} |metadata|, and an - {{IdentityProviderConfig}} |provider|, run the following steps [=in parallel=]: +[=AccountState=] |accountState|, {{IdentityProviderClientMetadata}} |metadata|, and an +{{IdentityProviderConfig}} |provider|, run the following steps [=in parallel=]: 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of |account|["{{IdentityProviderAccount/approved_clients}}"], then display the @@ -1576,10 +1586,11 @@ To fetch the client metadata given {{IdentityProviderAccount
-To select an account given an |accountsList|: +To select an account given an |accountsList|, run the following steps. This returns an +{{IdentityProviderAccount}} or null. 1. Assert |accountsList|'s [=list/size=] is greater than 1. 1. Display an account chooser displaying the options from |accountsList|. - 1. Let |account| be the {{IdentityProviderAccount/id}} of the account that the user + 1. Let |account| be the {{IdentityProviderAccount}} of the account that the user manually selects from the accounts chooser, or null if no account is selected. 1. Return |account|
@@ -1674,7 +1685,7 @@ partial interface IdentityCredential {
When the {{IdentityCredential/logoutRPs()}} method is invoked given a [=list=] of {{IdentityCredentialLogoutRPsRequest}}s |logoutRequests|, the user agent MUST execute the following -steps: +steps. This returns a {{Promise}}. 1. Let |promise| be a new {{Promise}}. 1. For each |request| in |logoutRequests|: 1. Let |rpOrigin| be [=this=]'s [=Document/origin=]. @@ -2204,7 +2215,7 @@ The [=user agent=] uses the following [=maybe fetch the accounts list=] instead
To maybe fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest| and an {{IdentityProviderConfig}} - |provider|: +|provider|, run the following steps. This returns a [=list=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. @@ -2236,7 +2247,7 @@ To maybe fetch the accounts list given an {{IdentityProviderAPIConfig
To Sign-in to the IDP given an {{IdentityProviderAPIConfig}} |manifest| and an {{IdentityProviderConfig}} - |provider|: +|provider|. This returns a [=list=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. Let |idpOrigin| be the origin corresponding to |configUrl|. From b60e92423534dfb359b9f84b42227159523a8fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Thu, 5 Jan 2023 18:29:10 -0500 Subject: [PATCH 06/17] b --- spec/index.bs | 94 ++++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 0cd4f78a7..427a86422 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1191,8 +1191,8 @@ requests.
When the {{IdentityCredential}}'s \[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) -algorithm is invoked, the user agent MUST execute the following steps (note that these are invoked while [=in parallel=]). -This returns an {{IdentityCredential}}, null, or an error. +algorithm is invoked, the user agent MUST execute the following steps. This returns an +{{IdentityCredential}}, null, or an error. 1. Assert: These steps are running [=in parallel=]. 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=map/exists=]. @@ -1209,7 +1209,7 @@ This returns an {{IdentityCredential}}, null, or an error. method to return null. If there was no such timer, the developer could easily infer whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=]. 1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0]. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] to + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to [=check the well-known file=] algorithm with |provider| and |globalObject|. Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} @@ -1251,31 +1251,27 @@ To check the well-known file given an {{IdentityProviderConfig}} |pro :: "no-referrer" : [=request/credentials mode=] :: "omit" - - Note: The spec is yet to be updated so that all requests are created - with [=request/mode=] set to "unsafe-no-cors". See the relevant - [pull request](https://github.com/whatwg/fetch/pull/1533) for details. + + Note: The spec is yet to be updated so that all requests are created + with [=request/mode=] set to "unsafe-no-cors". See the relevant + [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. Let |check| be false. - 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the - following steps: - 1. [=Fetch=] |request| with processResponseConsumeBody set to the - following steps given a response |response|: - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| - to perform the following steps: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, - |discovery|. - 1. Let |check| be set as follows: - 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] - is greater than 1, set |check| to false. - - Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the - provider_urls array. - - 1. Otherwise, set |check| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] - [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. - 1. Run [=on well-known check completed=], passing |check|, |provider|, and |globalObject|. + 1. [=Fetch=] |request| with processResponseConsumeBody set to the + following steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, + |discovery|. + 1. Let |check| be set as follows: + 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] + is greater than 1, set |check| to false. + + Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the + provider_urls array. + + 1. Otherwise, set |check| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] + [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. + 1. Run [=on well-known check completed=], passing |check|, |provider|, and |globalObject|.
@@ -1346,6 +1342,7 @@ manipulation to fingerprint. See [[#manifest-fingerprinting]].
To fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} |provider| and a |globalObject|: + 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. 1. If |accountsUrl| is failure, return an empty list. @@ -1410,7 +1407,8 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |ma 1. Wait until the user agent's dialog is closed and |accountState| has been updated. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new "{{AbortError}}" {{DOMException}}. - 1. Run the [=create tokens=] algorithm with |accountState|, |account|'s + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to run + the [=create tokens=] algorithm with |accountState|, |account|'s {{IdentityProviderAccount/id}}, |provider|, |manifest|, and |globalObject|.
@@ -1418,6 +1416,7 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |ma To create tokens given an [=AccountState=] |accountState|, a {{USVString}} |accountId|, an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |manifest|, and a |globalObject|: + 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Assert |accountState|'s {{AccountState/registration state}} is [=registered=]. 1. Assert |accountState|'s {{AccountState/allows logout}} is true. 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider| and @@ -1454,16 +1453,16 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr : [=request/credentials mode=] :: "include" - 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |token|. - 1. Run [=on token created=] given |token| and |globalObject|. + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |token|. + 1. Run [=on token created=] given |token| and |globalObject|.
On token created, given an {{IdentityProviderToken}} |token| and a |globalObject|: + 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Create a new {{IdentityCredential}} given |globalObject|'s realm. 1. Set |credential|'s {{IdentityCredential/token}} to |token|. 1. [=In parallel=], pass |credential| to the {{Credential/[[DiscoverFromExternalSource]]}} @@ -1474,9 +1473,12 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr To compute account state given an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps. This returns an [=AccountState=]. - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s + 1. Assert: These steps are running [=in parallel=]. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + compute |configUrl| as the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. - 1. Let |idpOrigin| be the [=origin=] corresponding to |configUrl|. + 1. Wait for the above task to run, and let |idpOrigin| be the [=origin=] corresponding to + |configUrl|. 1. Let |rpOrigin| be |globalObject|'s [=associated Document=]'s [=Document/origin=]. 1. Let |accountId| be |account|'s {{IdentityProviderAccount/id}}. 1. Let |triple| be (|rpOrigin|, |idpOrigin|, |accountId|). @@ -1490,6 +1492,7 @@ an [=AccountState=]. When computing the manifest URL given an {{IdentityProviderConfig}} |provider| and a [=string=] |manifestString|, perform the following steps. This returns a URL or failure. + 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. Let |manifestUrl| be the result of running [=url parser=] given |manifestString|. @@ -1507,6 +1510,7 @@ failure.
To extract the JSON fetch response given a response |response|, run the following steps. This returns an [=ordered map=] or null. + 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. If |response| is a [=network error=] or its [=response/status=] is not an [=ok status=], return null. 1. Let |mimeType| be the result of extracting a MIME TYPE from |response|'s @@ -1522,7 +1526,9 @@ run the following steps. This returns an [=ordered map=] or null. To request permission to sign-up the user with a given an {{IdentityProviderAccount}} |account|, an [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} |provider|, and a |globalObject|: - 1. Run the [=fetch the client metadata=] algorithm with |account|, |accountState|, |manifest|, + 1. Assert: These steps are running [=in parallel=]. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + [=fetch the client metadata=] algorithm with |account|, |accountState|, |manifest|, |provider|, and |globalObject|.
@@ -1530,6 +1536,7 @@ To request permission to sign-up the user with a given an {{IdentityP To fetch the client metadata given {{IdentityProviderAccount}} |account|, an [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps: + 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. 1. If |clientMetadataUrl| is failure, return null. @@ -1557,12 +1564,11 @@ To fetch the client metadata given {{IdentityProviderAccount : [=request/credentials mode=] :: "omit" - 1. [=Queue a global task=] on the [=networking task source=] given |globalObject| to perform the following steps: - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, |clientMetadata|. - 1. Run [=on client metadata fetched=], passing |account|, |accountState|, |clientMetadata|, and |provider|. + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, |clientMetadata|. + 1. Run [=on client metadata fetched=], passing |account|, |accountState|, |clientMetadata|, and |provider|.
@@ -1588,15 +1594,17 @@ To fetch the client metadata given {{IdentityProviderAccount
To select an account given an |accountsList|, run the following steps. This returns an {{IdentityProviderAccount}} or null. + 1. Assert: These steps are running [=in parallel=]. 1. Assert |accountsList|'s [=list/size=] is greater than 1. 1. Display an account chooser displaying the options from |accountsList|. 1. Let |account| be the {{IdentityProviderAccount}} of the account that the user manually selects from the accounts chooser, or null if no account is selected. - 1. Return |account| + 1. Return |account|.
To sign-in the user with a given an [=AccountState=] |accountState|: + 1. Assert: These steps are running [=in parallel=]. 1. Assert that |accountState|'s {{AccountState/registration state}} is [=registered=] 1. Change |accountState|'s {{AccountState/allows logout}} from false to true.
From 6cdf61598a485f3529823405df24b55a8c421ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Thu, 5 Jan 2023 18:31:40 -0500 Subject: [PATCH 07/17] b --- spec/index.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 427a86422..49b5c429f 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1252,9 +1252,9 @@ To check the well-known file given an {{IdentityProviderConfig}} |pro : [=request/credentials mode=] :: "omit" - Note: The spec is yet to be updated so that all requests are created +

The spec is yet to be updated so that all requests are created with [=request/mode=] set to "unsafe-no-cors". See the relevant - [pull request](https://github.com/whatwg/fetch/pull/1533) for details. + [pull request](https://github.com/whatwg/fetch/pull/1533) for details.

1. Let |check| be false. 1. [=Fetch=] |request| with processResponseConsumeBody set to the @@ -1529,13 +1529,13 @@ To request permission to sign-up the user with a given an {{IdentityP 1. Assert: These steps are running [=in parallel=]. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to [=fetch the client metadata=] algorithm with |account|, |accountState|, |manifest|, - |provider|, and |globalObject|. + |provider|.
To fetch the client metadata given {{IdentityProviderAccount}} |account|, an [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an -{{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps: +{{IdentityProviderConfig}} |provider|, run the following steps: 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and |manifest|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. From 59cf326c9bac13b07372c7ac6fb2de7b511194c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Fri, 6 Jan 2023 10:13:06 -0500 Subject: [PATCH 08/17] b --- spec/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/index.bs b/spec/index.bs index 49b5c429f..dc7b14e50 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1215,7 +1215,7 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} algorithm. See issue. 1. Wait until an error is thrown or an {{IdentityCredential}} credential - is returned. + is returned, and return it here.
From ed42ed3510f6be26166ee5c4dc6be6fdaeddef5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Mon, 9 Jan 2023 16:28:14 -0500 Subject: [PATCH 09/17] b --- spec/index.bs | 237 ++++++++++++++++++++++++-------------------------- 1 file changed, 115 insertions(+), 122 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index dc7b14e50..7f1d42013 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -756,7 +756,7 @@ For example: "color": "0xFFEEAA", "icons": [{ "url": "https://idp.example/icon.ico", - "size": 25 + "size": 25 }] } } @@ -1194,33 +1194,80 @@ When the {{IdentityCredential}}'s algorithm is invoked, the user agent MUST execute the following steps. This returns an {{IdentityCredential}}, null, or an error. - 1. Assert: These steps are running [=in parallel=]. - 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=map/exists=]. - 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=list/size=] is 1. - - Issue: Support choosing accounts from multiple [=Identity Provider=]s, as described [here](https://github.com/fedidcg/FedCM/issues/319). - 1. Run {{setTimeout}} passing a [=task=] which throws a {{NetworkError}}, after a timeout of - 60 seconds. - - Issue: Do not use {{setTimeout}} directly, as that is not correct. See the relevant - [issue](https://github.com/fedidcg/FedCM/issues/389). - - Note: the purpose of having a timer here is to avoid leaking the reason causing this - method to return null. If there was no such timer, the developer could easily infer - whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=]. - 1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0]. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - [=check the well-known file=] algorithm with |provider| and |globalObject|. - - Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} - algorithm. See issue. - 1. Wait until an error is thrown or an {{IdentityCredential}} credential - is returned, and return it here. + 1. Assert: These steps are running [=in parallel=]. + 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=map/exists=]. + 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=list/size=] is 1. + + Issue: Support choosing accounts from multiple [=Identity Provider=]s, as described [here](https://github.com/fedidcg/FedCM/issues/319). + 1. Run {{setTimeout}} passing a [=task=] which throws a {{NetworkError}}, after a timeout of + 60 seconds. + + Issue: Do not use {{setTimeout}} directly, as that is not correct. See the relevant + [issue](https://github.com/fedidcg/FedCM/issues/389). + + Note: the purpose of having a timer here is to avoid leaking the reason causing this + method to return null. If there was no such timer, the developer could easily infer + whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=]. + 1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0]. + 1. Let |outputCredential| be null. + 1. Run the [=potentially create an IdentityCredential=] algorithm with |provider|, + |globalObject|, and |outputCredential|. + + Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} + algorithm. See issue. + + 1. Wait until an error is thrown or |outputCredential| becomes non-null. + 1. Assert: |outputCredential| is an {{IdentityCredential}}. + 1. Return |outputCredential|. +
+ +
+To potentially create an IdentityCredential given an {{IdentityProviderConfig}} +|provider|, |globalObject|, and |outputCredential|, run the following steps: + 1. Assert: These steps are running [=in parallel=]. + 1. Let |check| be null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + [=check the well-known file=] with |provider| and |check|. + 1. Let |config| be null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + [=fetch the config file=] with |provider| and |config|. + 1. Wait for |check| and |config| to become non-null (or for errors to be thrown). + 1. Assert: |check| is true and |config| is an {{IdentityProviderAPIConfig}}. + 1. Let |accountsList| be null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + [=fetch the accounts list=] algorithm with |config|, |provider|, and |accountsList|. + 1. Wait for |accountsList| to become non-null. + 1. Assert: |accountsList| is an {{IdentityProviderAccountList}}. + 1. If |accountsList|'s size is 1: + 1. Let |account| be |accountsList|[0]. + 1. Let |accountState| be the result of running the [=compute account state=] algorithm + given |provider|, |account|, and |globalObject|. + 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the + [=request permission to sign-up=] algorithm with |account|, |accountState|, |config|, + |provider|, and |globalObject|. + 1. Otherwise, show a dialog to request user permission to sign in via |account|. + 1. If the user grants permission, run the [=sign-in=] algorithm with |accountState|. + 1. Otherwise: + 1. Let |account| be the result of running the [=select an account=] from the + |accountsList|. + 1. If |account| is null, return null. + 1. Let |accountState| be the result of running the [=compute account state=] algorithm + given |provider| and |account|. + 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the + [=request permission to sign-up=] algorithm with |account|, |accountState|, |config|, + |provider|, and |globalObject|. + 1. Otherwise, run the [=sign-in=] algorithm with |accountState|. + 1. Wait until the [=user agent=]'s dialog is closed and |accountState| has been updated. + 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new + "{{AbortError}}" {{DOMException}}. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to run + the [=create tokens=] algorithm with |accountState|, |account|'s + {{IdentityProviderAccount/id}}, |provider|, |config|, |globalObject|, and |outputCredential|.
-To check the well-known file given an {{IdentityProviderConfig}} |provider| and a -|globalObject|, run the following steps: +To check the well-known file given an {{IdentityProviderConfig}} |provider| and +|outputCheck|, run the following steps: 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. @@ -1256,37 +1303,26 @@ To check the well-known file given an {{IdentityProviderConfig}} |pro with [=request/mode=] set to "unsafe-no-cors". See the relevant [pull request](https://github.com/whatwg/fetch/pull/1533) for details.

- 1. Let |check| be false. 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, |discovery|. - 1. Let |check| be set as follows: + 1. Set |outputCheck| as follows: 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] - is greater than 1, set |check| to false. + is greater than 1, set |outputCheck| to false. Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the provider_urls array. - 1. Otherwise, set |check| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] + 1. Otherwise, set |outputCheck| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. - 1. Run [=on well-known check completed=], passing |check|, |provider|, and |globalObject|. -
- -
-On well-known check completed, given a boolean |check|, an {{IdentityProviderConfig}} -|provider| and a |globalObject|: - 1. If |check| is false, throw a "{{NetworkError}}" {{DOMException}}. - 1. Run [=fetch the internal manifest=], passing |provider| and |globalObject|. + 1. If |outputCheck| is false, throw a "{{NetworkError}}" {{DOMException}}.
-NOTE: The well-known file and internal manifest fetches could be performed simultaneously, it is -just simpler to specify these as happening one after the other. -
-To fetch the internal manifest algorithm given an {{IdentityProviderConfig}} |provider| -and a |globalObject|: +To fetch the config file algorithm given an {{IdentityProviderConfig}} |provider|, +and an |outputConfig|: 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. @@ -1321,30 +1357,25 @@ and a |globalObject|: 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}}, |manifest|. - 1. Run [=on internal manifest fetched=], passing |manifest|, provider|, and |globalObject|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}} stored + in |outputConfig|. + 1. If |outputConfig| is null, throw a "{{NetworkError}}" {{DOMException}}.
-NOTE: We use a two-tier manifest list in order to prevent the [=IDP=] to easily determine the [=RP=] -that a user is visiting by encoding the information in the manifest path. We solve this issue by -requiring a manifest list to be on the root of the [=IDP=]. The manifest itself can be anywhere, but -it will not be used if the user agent does not find it in the manifest list. This allows the [=IDP=] -to keep their actual manifest on an arbitary path while allowing the user agent to prevent manifest -manipulation to fingerprint. See [[#manifest-fingerprinting]]. +NOTE: We use a two-tier file system in order to prevent the [=IDP=] to easily determine the [=RP=] +that a user is visiting by encoding the information in the config file path. We solve this issue by +requiring a well-known file to be on the root of the [=IDP=]. The config file itself can be anywhere, but +it will not be used if the user agent does not find it in the well-known file. This allows the [=IDP=] +to keep their actual config files on an arbitary path while allowing the user agent to prevent config file +path manipulation to fingerprint (for instance, by including the RP in the path). See +[[#manifest-fingerprinting]].
-On internal manifest fetched, given an {{IdentityProviderAPIConfig}} |manifest|, an -{{IdentityProviderConfig}} |provider| and a |globalObject|: - 1. If |manifest| is null, throw a "{{NetworkError}}" {{DOMException}}. - 1. Run the [=fetch the accounts list=] algorithm with |manifest|, |provider|, and |globalObject|. -
- -
-To fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest|, an -{{IdentityProviderConfig}} |provider| and a |globalObject|: +To fetch the accounts list given an {{IdentityProviderAPIConfig}} |config|, an +{{IdentityProviderConfig}} |provider|, and |outputAccountsList|: 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider| and - |manifest|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. + |config|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. 1. If |accountsUrl| is failure, return an empty list. 1. Let |request| be a new request as follows: @@ -1375,52 +1406,21 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |ma 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, |accountsList|. - 1. Run [=on accounts list fetched=], passing |accountsList|, |manifest|, |provider|, and |globalObject|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, and + store the result in |outputAccountsList|. Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336).
-
-On accounts list fetched, given an {{IdentityProviderAccountList}} |accountsList|, an -{{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} |provider| and a -|globalObject|, run the following steps [=in parallel=]: - 1. If |accountsList|'s size is 1: - 1. Let |account| be |accountsList|[0]. - 1. Let |accountState| be the result of running the [=compute account state=] algorithm - given |provider|, |account|, and |globalObject|. - 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the - [=request permission to sign-up=] algorithm with |account|, |accountState|, |manifest|, - |provider|, and |globalObject|. - 1. Otherwise, show a dialog to request user permission to sign in via |account|. - 1. If the user grants permission, run the [=sign-in=] algorithm with |accountState|. - 1. Otherwise: - 1. Let |account| be the result of running the [=select an account=] from the - |accountsList|. - 1. If |account| is null, return null. - 1. Let |accountState| be the result of running the [=compute account state=] algorithm - given |provider| and |account|. - 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the - [=request permission to sign-up=] algorithm with |account|, |accountState|, |manifest|, - |provider|, and |globalObject|. - 1. Otherwise, run the [=sign-in=] algorithm with |accountState|. - 1. Wait until the user agent's dialog is closed and |accountState| has been updated. - 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new - "{{AbortError}}" {{DOMException}}. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to run - the [=create tokens=] algorithm with |accountState|, |account|'s - {{IdentityProviderAccount/id}}, |provider|, |manifest|, and |globalObject|. -
-
To create tokens given an [=AccountState=] |accountState|, a {{USVString}} |accountId|, - an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |manifest|, and a - |globalObject|: + an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |config|, + |globalObject|, and |outputCredential|: 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Assert |accountState|'s {{AccountState/registration state}} is [=registered=]. 1. Assert |accountState|'s {{AccountState/allows logout}} is true. 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider| and - |manifest|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"]. + |config|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"]. 1. If |idTokenUrl| is failure, return null. 1. Let |requestBody| be a [=string=] resulting in concatenating "client_id=", |provider|'s {{IdentityProviderConfig/clientId}}, "&nonce=", @@ -1457,16 +1457,9 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |token|. - 1. Run [=on token created=] given |token| and |globalObject|. -
- -
-On token created, given an {{IdentityProviderToken}} |token| and a |globalObject|: - 1. Assert: These steps are running on the [=DOM manipulation task source=]. - 1. Create a new {{IdentityCredential}} given |globalObject|'s realm. - 1. Set |credential|'s {{IdentityCredential/token}} to |token|. - 1. [=In parallel=], pass |credential| to the {{Credential/[[DiscoverFromExternalSource]]}} - callback. + 1. Let |outputCredential| be a new {{IdentityCredential}} given |globalObject|'s + realm. + 1. Set |outputCredential|'s {{IdentityCredential/token}} to |token|.
@@ -1498,7 +1491,7 @@ failure. 1. Let |manifestUrl| be the result of running [=url parser=] given |manifestString|. 1. If |manifestUrl| is failure, let |manifestUrl| be the result of running [=url parser=] given |manifestString| (the relative URL) and |configUrl| (the base URL). - + Note: This means the we allow passing the manifest string as either an absolute or relative URL. 1. If |manifestUrl| is failure, return failure. @@ -1524,21 +1517,21 @@ run the following steps. This returns an [=ordered map=] or null.
To request permission to sign-up the user with a given an {{IdentityProviderAccount}} |account|, an -[=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an {{IdentityProviderConfig}} +[=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |config|, an {{IdentityProviderConfig}} |provider|, and a |globalObject|: 1. Assert: These steps are running [=in parallel=]. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - [=fetch the client metadata=] algorithm with |account|, |accountState|, |manifest|, + [=fetch the client metadata=] algorithm with |account|, |accountState|, |config|, |provider|.
To fetch the client metadata given {{IdentityProviderAccount}} |account|, an -[=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |manifest|, an +[=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |config|, an {{IdentityProviderConfig}} |provider|, run the following steps: 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and - |manifest|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. + |config|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. 1. If |clientMetadataUrl| is failure, return null. 1. Let |request| be a new request as follows: @@ -1659,7 +1652,7 @@ through an [[#use-cases-sign-in]] upon return. +------->| Registered RPs |-------+------->| Queue | | | | | +------------------------+ +-------+ - + @@ -1770,15 +1763,15 @@ separate section for [[#privacy]] considerations. The first fetches triggered by the FedCM API are the manifest list, which is public, and the -internal manifest. Imagine a malicious script included by (and running as) the [=RP=] attempting to +config file. Imagine a malicious script included by (and running as) the [=RP=] attempting to execute the FedCM API calls to a malicious [=IDP=], one which is not trusted by the [=RP=]. If the call is successful, this would introduce browser UI on the [=RP=] with sign in options into a malicious [=IDP=]. This malicious[=IDP=] could then attempt to trick the user. The protection against this attack is the [[!CSP]] check, which would fail because the origin of the manifest of the malicious [=IDP=] would not be an origin included in the allowlist specified by the [[!CSP]] of the [=RP=], hence preventing the undesired FedCM UI from being shown. Since any subsequent fetches -are same origin with respect to the internal manifest or at least dependent on the contents of the -internal manifest, they do not require additional checks. +are same origin with respect to the config file or at least dependent on the contents of the +config file, they do not require additional checks. The non-same-origin fetches include, for example, the brand icon. The user agent does not perform a [[!CSP]] check on these because they are directly specified from the manifest. In addition, the @@ -1968,7 +1961,7 @@ these scenarios consider how user tracking might happen **without** them. See al ### Manifest Fingerprinting ### {#manifest-fingerprinting} -Suppose that the FedCM API did not have a two-tier manifest (see the [=on well-known check completed=] +Suppose that the FedCM API did not have a two-tier manifest (see the [=potentially create an IdentityCredential=] algorithm), and instead directly had a single manifest. This would introduce the following fingerprinting attack: @@ -2222,7 +2215,7 @@ IDPs are also offered an extension to the {{IdentityProviderAPIConfig}} object t The [=user agent=] uses the following [=maybe fetch the accounts list=] instead of the [=fetch the accounts list=] algorithm. It would also return early on if the user was {{Sign-in Status/signed-out}}.
-To maybe fetch the accounts list given an {{IdentityProviderAPIConfig}} |manifest| and an {{IdentityProviderConfig}} +To maybe fetch the accounts list given an {{IdentityProviderAPIConfig}} |config| and an {{IdentityProviderConfig}} |provider|, run the following steps. This returns a [=list=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s @@ -2230,7 +2223,7 @@ To maybe fetch the accounts list given an {{IdentityProviderAPIConfig 1. Let |idpOrigin| be the origin corresponding to |configUrl|. 1. Let |status| be the [=Sign-in Status=] of the |idpOrigin|. 1. If |status| is {{Sign-in Status/unknown}}: - 1. Let |accounts| be the result of the [=fetch the accounts list=] algorithm given |manifest| and |provider|. + 1. Let |accounts| be the result of the [=fetch the accounts list=] algorithm given |config| and |provider|. 1. Set the [=Sign-in Status=] of the |idpOrigin| to {{Sign-in Status/signed-in}} if |accounts| is non-empty, {{Sign-in Status/signed-out}} otherwise. NOTE: This handles the case where the [=IDP=] hasn't had the chance to call the API before the accounts list is needed. This can incur into a timing attack, but it is limited to 1 per [=IDP=] per [=user agent=], so not very practical. Albeit small, removing this attack surface is an active area of investigation. @@ -2241,12 +2234,12 @@ To maybe fetch the accounts list given an {{IdentityProviderAPIConfig NOTE: By terminating the request here before running [=fetch the accounts list=] algorithm we prevent the timing attack to be performed without any user prompt. 1. If |status| is {{Sign-in Status/signed-in}}: - 1. Let |accounts| be the result of the [=fetch the accounts list=] algorithm given |manifest| and |provider|. + 1. Let |accounts| be the result of the [=fetch the accounts list=] algorithm given |config| and |provider|. 1. If |accounts|'s size is 0: 1. Set the [=Sign-in Status=] of the |idpOrigin| to {{Sign-in Status/signed-out}}. 1. Ask the user to confirm they want to sign-in to their [=IDP=]. 1. If they decline, return an empty list. - 1. Return the result of running the [=Sign-in to the IDP=] algorithm given |manifest| and |provider|. + 1. Return the result of running the [=Sign-in to the IDP=] algorithm given |config| and |provider|. NOTE: This can happen when the user's local client credentials are invalidated on the server (e.g. changing passwords or deleting accounts on a different device), or we get network errors (e.g. timeouts, failures, etc). @@ -2254,14 +2247,14 @@ To maybe fetch the accounts list given an {{IdentityProviderAPIConfig
-To Sign-in to the IDP given an {{IdentityProviderAPIConfig}} |manifest| and an {{IdentityProviderConfig}} +To Sign-in to the IDP given an {{IdentityProviderAPIConfig}} |config| and an {{IdentityProviderConfig}} |provider|. This returns a [=list=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. Let |idpOrigin| be the origin corresponding to |configUrl|. 1. Assert that the [=Sign-in Status=] of the |idpOrigin| is {{Sign-in Status/signed-out}}. 1. In parallel, wait until one of the following tasks returns to continue: - 1. Open a dialog that directs the user to the |manifest|'s {{IdentityProviderAPIConfig/signin_url}}. + 1. Open a dialog that directs the user to the |config|'s {{IdentityProviderAPIConfig/signin_url}}. 1. Wait until the [=Sign-in Status=] of the |idpOrigin| becomes {{Sign-in Status/signed-in}} 1. Close the dialog 1. Return the result of the [=fetch the accounts list=] algorithm From 8609baddb13f730d85bd8ccb66a4c258906d6e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Mon, 9 Jan 2023 20:18:57 -0500 Subject: [PATCH 10/17] b --- spec/index.bs | 194 +++++++++++++++++++++++++++----------------------- 1 file changed, 103 insertions(+), 91 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 7f1d42013..5967467c4 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1192,7 +1192,7 @@ requests. When the {{IdentityCredential}}'s \[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) algorithm is invoked, the user agent MUST execute the following steps. This returns an -{{IdentityCredential}}, null, or an error. +{{IdentityCredential}} (or throws an error to the caller). 1. Assert: These steps are running [=in parallel=]. 1. Assert: |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"] [=map/exists=]. @@ -1206,68 +1206,67 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu [issue](https://github.com/fedidcg/FedCM/issues/389). Note: the purpose of having a timer here is to avoid leaking the reason causing this - method to return null. If there was no such timer, the developer could easily infer + method to throw an error. If there was no such timer, the developer could easily infer whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=]. 1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0]. - 1. Let |outputCredential| be null. - 1. Run the [=potentially create an IdentityCredential=] algorithm with |provider|, - |globalObject|, and |outputCredential|. + 1. Return the result of running [=create an IdentityCredential=] with |provider| and + |globalObject|. Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} algorithm. See issue. - - 1. Wait until an error is thrown or |outputCredential| becomes non-null. - 1. Assert: |outputCredential| is an {{IdentityCredential}}. - 1. Return |outputCredential|.
-To potentially create an IdentityCredential given an {{IdentityProviderConfig}} -|provider|, |globalObject|, and |outputCredential|, run the following steps: +To create an IdentityCredential given an {{IdentityProviderConfig}} +|provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}}. 1. Assert: These steps are running [=in parallel=]. - 1. Let |check| be null. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - [=check the well-known file=] with |provider| and |check|. - 1. Let |config| be null. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - [=fetch the config file=] with |provider| and |config|. - 1. Wait for |check| and |config| to become non-null (or for errors to be thrown). + 1. Let |check|, |config| be variables initially null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| and + run the following steps: + 1. Set |check| to the result of [=check the well-known file=] with |provider|. + 1. Set |config| to the result of [=fetch the config file=] with |provider|. + 1. Wait for |check| and |config| to become non-null. 1. Assert: |check| is true and |config| is an {{IdentityProviderAPIConfig}}. 1. Let |accountsList| be null. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - [=fetch the accounts list=] algorithm with |config|, |provider|, and |accountsList|. + set |accountsList| to the result of [=fetch the accounts list=] with |config| and |provider|. 1. Wait for |accountsList| to become non-null. 1. Assert: |accountsList| is an {{IdentityProviderAccountList}}. 1. If |accountsList|'s size is 1: 1. Let |account| be |accountsList|[0]. 1. Let |accountState| be the result of running the [=compute account state=] algorithm given |provider|, |account|, and |globalObject|. - 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the + 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=], [=request permission to sign-up=] algorithm with |account|, |accountState|, |config|, - |provider|, and |globalObject|. - 1. Otherwise, show a dialog to request user permission to sign in via |account|. - 1. If the user grants permission, run the [=sign-in=] algorithm with |accountState|. + |provider|, and |globalObject| and set the result in |permission|. + 1. Otherwise, show a dialog to request user permission to sign in via |account|, and set the + result in |permission|. + 1. If |permission|, [=sign-in=] with |accountState|. 1. Otherwise: 1. Let |account| be the result of running the [=select an account=] from the |accountsList|. - 1. If |account| is null, return null. 1. Let |accountState| be the result of running the [=compute account state=] algorithm given |provider| and |account|. - 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then run the - [=request permission to sign-up=] algorithm with |account|, |accountState|, |config|, - |provider|, and |globalObject|. - 1. Otherwise, run the [=sign-in=] algorithm with |accountState|. + 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=]: + 1. Run the [=request permission to sign-up=] algorithm with |account|, |accountState|, + |config|, |provider|, and |globalObject| and set the result in |permission|. + 1. If |permission|, [=sign-in=] with |accountState|. + 1. Otherwise, [=sign-in=] with |accountState|. 1. Wait until the [=user agent=]'s dialog is closed and |accountState| has been updated. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new - "{{AbortError}}" {{DOMException}}. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to run - the [=create tokens=] algorithm with |accountState|, |account|'s - {{IdentityProviderAccount/id}}, |provider|, |config|, |globalObject|, and |outputCredential|. + "{{NetworkError}}" {{DOMException}}. + 1. Let |credential| be null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + set |credential| to the result of running [=create tokens=] algorithm with |accountState|, + |account|'s {{IdentityProviderAccount/id}}, |provider|, |config|, and |globalObject|. + 1. Wait until |credential| is not null. + 1. Assert: |credential| is an {{IdentityCredential}}. + 1. Return |credential|.
-To check the well-known file given an {{IdentityProviderConfig}} |provider| and -|outputCheck|, run the following steps: +To check the well-known file given an {{IdentityProviderConfig}} |provider|, run the +following steps. This returns a boolean. 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. @@ -1303,33 +1302,36 @@ To check the well-known file given an {{IdentityProviderConfig}} |pro with [=request/mode=] set to "unsafe-no-cors". See the relevant [pull request](https://github.com/whatwg/fetch/pull/1533) for details.

+ 1. Let |check| be null. 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, |discovery|. - 1. Set |outputCheck| as follows: + 1. Set |check| as follows: 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] - is greater than 1, set |outputCheck| to false. + is greater than 1, set |check| to false. Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the provider_urls array. - 1. Otherwise, set |outputCheck| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] + 1. Otherwise, set |check| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. - 1. If |outputCheck| is false, throw a "{{NetworkError}}" {{DOMException}}. + 1. If |check| is false, throw a "{{NetworkError}}" {{DOMException}}. + 1. [=In parallel=], wait until |check| becomes non-null, and return it.
To fetch the config file algorithm given an {{IdentityProviderConfig}} |provider|, -and an |outputConfig|: +run the following steps. This returns an {{IdentityProviderAPIConfig}}: 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. - 1. If |configUrl| is failure, return null. + 1. If |configUrl| is failure, throw a new "{{NetworkError}}" {{DOMException}}. 1. Run a [[!CSP]] check with a [[CSP#directive-connect-src|connect-src]] directive on the URL passed as |configUrl|. - 1. If |configUrl| is not a [=potentially trustworthy URL=], return null. + 1. If |configUrl| is not a [=potentially trustworthy URL=], throw a new "{{NetworkError}}" + {{DOMException}}. 1. Let |request| be a new request as follows: : [=request/url=] @@ -1354,12 +1356,13 @@ and an |outputConfig|: : [=request/credentials mode=] :: "omit" + 1. Let |config| be null. 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}} stored - in |outputConfig|. - 1. If |outputConfig| is null, throw a "{{NetworkError}}" {{DOMException}}. + in |config|. + 1. [=In parallel=], wait until |config| is not null, and return it.
NOTE: We use a two-tier file system in order to prevent the [=IDP=] to easily determine the [=RP=] @@ -1372,7 +1375,8 @@ path manipulation to fingerprint (for instance, by including the RP in the path)
To fetch the accounts list given an {{IdentityProviderAPIConfig}} |config|, an -{{IdentityProviderConfig}} |provider|, and |outputAccountsList|: +{{IdentityProviderConfig}} |provider|, run the following steps. This returns an +{{IdentityProviderAccountList}}. 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider| and |config|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. @@ -1403,25 +1407,28 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |co Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). + 1. Let |accountsList| be null. 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, and - store the result in |outputAccountsList|. + store the result in |accountsList|. Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336). + + 1. [=In parallel=], wait for |accountsList| to become non-null, and return it.
To create tokens given an [=AccountState=] |accountState|, a {{USVString}} |accountId|, - an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |config|, - |globalObject|, and |outputCredential|: + an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |config|, and + |globalObject|, run the following steps. This returns an {{IdentityCredential}}. 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Assert |accountState|'s {{AccountState/registration state}} is [=registered=]. 1. Assert |accountState|'s {{AccountState/allows logout}} is true. 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider| and |config|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"]. - 1. If |idTokenUrl| is failure, return null. + 1. If |idTokenUrl| is failure, throw a new "{{NetworkError}}" {{DOMException}}. 1. Let |requestBody| be a [=string=] resulting in concatenating "client_id=", |provider|'s {{IdentityProviderConfig/clientId}}, "&nonce=", |provider|'s {{IdentityProviderConfig/nonce}}, "&account_id=", and |accountId|. @@ -1453,13 +1460,15 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr : [=request/credentials mode=] :: "include" - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: - 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |token|. - 1. Let |outputCredential| be a new {{IdentityCredential}} given |globalObject|'s - realm. - 1. Set |outputCredential|'s {{IdentityCredential/token}} to |token|. + 1. Let |credential| be null. + 1. [=Fetch=] |request| with processResponseConsumeBody set to the following + steps given a response |response|: + 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |token|. + 1. Let |credential| be a new {{IdentityCredential}} given |globalObject|'s + realm. + 1. Set |credential|'s {{IdentityCredential/token}} to |token|. + 1. [=In parallel=], wait for |credential| to be non-null, and return it.
@@ -1502,37 +1511,57 @@ failure.
To extract the JSON fetch response given a response |response|, -run the following steps. This returns an [=ordered map=] or null. +run the following steps. This returns an [=ordered map=]. 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. If |response| is a [=network error=] or its [=response/status=] is not an [=ok status=], - return null. + throw a new "{{NetworkError}}" {{DOMException}}. 1. Let |mimeType| be the result of extracting a MIME TYPE from |response|'s header list. - 1. If |mimeType| is failure or is not a [=JSON MIME Type=], return null. + 1. If |mimeType| is failure or is not a [=JSON MIME Type=], throw a new "{{NetworkError}}" + {{DOMException}}. 1. Let |json| be the result of [=parse JSON bytes to an Infra value=] passing |response|'s [=response/body=]. - 1. If |json| is a parsing exception, or if |json| is not an [=ordered map=], return null. + 1. If |json| is a parsing exception, or if |json| is not an [=ordered map=], throw a new + "{{NetworkError}}" {{DOMException}}. 1. Return |json|.
To request permission to sign-up the user with a given an {{IdentityProviderAccount}} |account|, an [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |config|, an {{IdentityProviderConfig}} -|provider|, and a |globalObject|: +|provider|, and a |globalObject|, run the following steps. This returns a boolean. 1. Assert: These steps are running [=in parallel=]. + 1. Let |metadata| be false (|metadata| could be set to null, hence initialize differently here). 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - [=fetch the client metadata=] algorithm with |account|, |accountState|, |config|, - |provider|. + [=fetch the client metadata=] algorithm with |config| and |provider|, and set the result to + |metadata|. + 1. Wait until |metadata| is not false. + 1. Assert: |metadata| is null or an {{IdentityProviderClientMetadata}}. + 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s + {{IdentityProviderConfig/clientId}} is not in the list of + |account|["{{IdentityProviderAccount/approved_clients}}"], then display the + |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] link. + 1. If |metadata| is not null, |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] is defined, + and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of + |account|["{{IdentityProviderAccount/approved_clients}}"], then display the + |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] link. + 1. Prompt the user to gather explicit intent to create an account. The user agent MAY use the + {{IdentityProviderBranding}} to inform the style choices of its UI. + 1. If the user does not grant permission, return false. + 1. Change |accountState|'s {{AccountState/registration state}} from [=unregistered=] to + [=registered=]. + 1. Change |accountState|'s {{AccountState/allows logout}} from false to true. + 1. Return true.
-To fetch the client metadata given {{IdentityProviderAccount}} |account|, an -[=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |config|, an -{{IdentityProviderConfig}} |provider|, run the following steps: +To fetch the client metadata given an {{IdentityProviderAPIConfig}} |config| and +an {{IdentityProviderConfig}} |provider|, run the following steps. This returns an +{{IdentityProviderClientMetadata}}. 1. Assert: These steps are running on the [=DOM manipulation task source=]. 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and |config|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. - 1. If |clientMetadataUrl| is failure, return null. + 1. If |clientMetadataUrl| is failure, throw a new "{{NetworkError}}" {{DOMException}}. 1. Let |request| be a new request as follows: : [=request/url=] @@ -1557,41 +1586,24 @@ To fetch the client metadata given {{IdentityProviderAccount : [=request/credentials mode=] :: "omit" + 1. Let |metadata| be null. 1. [=Fetch=] |request| with processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. - 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, |clientMetadata|. - 1. Run [=on client metadata fetched=], passing |account|, |accountState|, |clientMetadata|, and |provider|. -
- -
-On client metadata fetched, given an {{IdentityProviderAccount}} |account|, an -[=AccountState=] |accountState|, {{IdentityProviderClientMetadata}} |metadata|, and an -{{IdentityProviderConfig}} |provider|, run the following steps [=in parallel=]: - 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s - {{IdentityProviderConfig/clientId}} is not in the list of - |account|["{{IdentityProviderAccount/approved_clients}}"], then display the - |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] link. - 1. If |metadata| is not null, |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] is defined, - and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of - |account|["{{IdentityProviderAccount/approved_clients}}"], then display the - |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] link. - 1. Prompt the user to gather explicit intent to create an account. The user agent MAY use the - {{IdentityProviderBranding}} to inform the style choices of its UI. - 1. If the user does not grants permission, return. - 1. Change |accountState|'s {{AccountState/registration state}} from [=unregistered=] to - [=registered=]. - 1. Change |accountState|'s {{AccountState/allows logout}} from false to true. + 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, + and store the result in |metadata|. + 1. [=In parallel=], wait until |metadata| becomes not null, and return it.
To select an account given an |accountsList|, run the following steps. This returns an -{{IdentityProviderAccount}} or null. +{{IdentityProviderAccount}}. 1. Assert: These steps are running [=in parallel=]. 1. Assert |accountsList|'s [=list/size=] is greater than 1. 1. Display an account chooser displaying the options from |accountsList|. 1. Let |account| be the {{IdentityProviderAccount}} of the account that the user - manually selects from the accounts chooser, or null if no account is selected. + manually selects from the accounts chooser, or throw a new "{{NetworkError}}" + {{DOMException}} if no account is selected. 1. Return |account|.
@@ -1961,7 +1973,7 @@ these scenarios consider how user tracking might happen **without** them. See al ### Manifest Fingerprinting ### {#manifest-fingerprinting} -Suppose that the FedCM API did not have a two-tier manifest (see the [=potentially create an IdentityCredential=] +Suppose that the FedCM API did not have a two-tier manifest (see the [=create an IdentityCredential=] algorithm), and instead directly had a single manifest. This would introduce the following fingerprinting attack: From bfa6071341681fadc4228ad2c0abd89842b3a4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Tue, 10 Jan 2023 11:07:42 -0500 Subject: [PATCH 11/17] b --- spec/index.bs | 95 +++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 5967467c4..6b4b0eedc 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1220,18 +1220,14 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu To create an IdentityCredential given an {{IdentityProviderConfig}} |provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}}. 1. Assert: These steps are running [=in parallel=]. - 1. Let |check|, |config| be variables initially null. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| and - run the following steps: - 1. Set |check| to the result of [=check the well-known file=] with |provider|. - 1. Set |config| to the result of [=fetch the config file=] with |provider|. - 1. Wait for |check| and |config| to become non-null. - 1. Assert: |check| is true and |config| is an {{IdentityProviderAPIConfig}}. - 1. Let |accountsList| be null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + set |check| to the result of [=check the well-known file=] with |provider|. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + set |config| to the result of [=fetch the config file=] with |provider|. + 1. Wait until |check| and |config| are set. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to set |accountsList| to the result of [=fetch the accounts list=] with |config| and |provider|. - 1. Wait for |accountsList| to become non-null. - 1. Assert: |accountsList| is an {{IdentityProviderAccountList}}. + 1. Wait until |accountsList| is set. 1. If |accountsList|'s size is 1: 1. Let |account| be |accountsList|[0]. 1. Let |accountState| be the result of running the [=compute account state=] algorithm @@ -1255,12 +1251,10 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} 1. Wait until the [=user agent=]'s dialog is closed and |accountState| has been updated. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new "{{NetworkError}}" {{DOMException}}. - 1. Let |credential| be null. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to set |credential| to the result of running [=create tokens=] algorithm with |accountState|, |account|'s {{IdentityProviderAccount/id}}, |provider|, |config|, and |globalObject|. - 1. Wait until |credential| is not null. - 1. Assert: |credential| is an {{IdentityCredential}}. + 1. Wait until |credential| is set. 1. Return |credential|.
@@ -1479,7 +1473,7 @@ an [=AccountState=]. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to compute |configUrl| as the result of running [=url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. - 1. Wait for the above task to run, and let |idpOrigin| be the [=origin=] corresponding to + 1. Wait until |configUrl| is set, and let |idpOrigin| be the [=origin=] corresponding to |configUrl|. 1. Let |rpOrigin| be |globalObject|'s [=associated Document=]'s [=Document/origin=]. 1. Let |accountId| be |account|'s {{IdentityProviderAccount/id}}. @@ -1531,11 +1525,10 @@ To request permission to sign-up the user with a given an {{IdentityP [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |config|, an {{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps. This returns a boolean. 1. Assert: These steps are running [=in parallel=]. - 1. Let |metadata| be false (|metadata| could be set to null, hence initialize differently here). 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to [=fetch the client metadata=] algorithm with |config| and |provider|, and set the result to |metadata|. - 1. Wait until |metadata| is not false. + 1. Wait until |metadata| is set. 1. Assert: |metadata| is null or an {{IdentityProviderClientMetadata}}. 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of @@ -1700,39 +1693,43 @@ When the {{IdentityCredential/logoutRPs()}} method is invoked given a [=list=] o {{IdentityCredentialLogoutRPsRequest}}s |logoutRequests|, the user agent MUST execute the following steps. This returns a {{Promise}}. 1. Let |promise| be a new {{Promise}}. - 1. For each |request| in |logoutRequests|: - 1. Let |rpOrigin| be [=this=]'s [=Document/origin=]. - 1. Let |idpOrigin| be |request|'s {{IdentityCredentialLogoutRPsRequest/url}}'s [=origin=]. - 1. Let |account| be |request|'s {{IdentityCredentialLogoutRPsRequest/accountId}}. - 1. Let |triple| be (|rpOrigin|, |idpOrigin|, |account|). - 1. If [=state machine map=][|triple|] does not exist, continue. - 1. Let |accountState| be [=state machine map=][|triple|]. - 1. If the |accountState|'s {{AccountState/registration state}} is [=unregistered=] or - |accountState|'s {{AccountState/allows logout}} is false, continue. - 1. Let |fetchRequest| be a new request as follows: - - : [=request/url=] - :: |request|'s {{IdentityCredentialLogoutRPsRequest/url}} - : [=request/mode=] - :: "GET" - : [=request/redirect mode=] - :: "error" - : [=request/client=] - :: null - : [=request/window=] - :: "no-window" - : [=request/service-workers mode=] - :: "none" - : [=request/destination=] - :: "webidentity" - : [=request/origin=] - :: a unique [=opaque origin=] - : [=request/credentials mode=] - :: "include" - - 1. [=Fetch=] |fetchRequest|. - 1. Set the |accountState| {{AccountState/allows logout}} to false. - 1. Resolve |promise| with [undefined] and return |promise|. + 1. Let |globalObject| be this's relevant global object. + 1. [=In parallel=], perform the following steps: + 1. For each |request| in |logoutRequests|: + 1. Let |rpOrigin| be [=this=]'s [=Document/origin=]. + 1. Let |idpOrigin| be |request|'s {{IdentityCredentialLogoutRPsRequest/url}}'s [=origin=]. + 1. Let |account| be |request|'s {{IdentityCredentialLogoutRPsRequest/accountId}}. + 1. Let |triple| be (|rpOrigin|, |idpOrigin|, |account|). + 1. If [=state machine map=][|triple|] does not exist, continue. + 1. Let |accountState| be [=state machine map=][|triple|]. + 1. If the |accountState|'s {{AccountState/registration state}} is [=unregistered=] or + |accountState|'s {{AccountState/allows logout}} is false, continue. + 1. Let |fetchRequest| be a new request as follows: + + : [=request/url=] + :: |request|'s {{IdentityCredentialLogoutRPsRequest/url}} + : [=request/mode=] + :: "GET" + : [=request/redirect mode=] + :: "error" + : [=request/client=] + :: null + : [=request/window=] + :: "no-window" + : [=request/service-workers mode=] + :: "none" + : [=request/destination=] + :: "webidentity" + : [=request/origin=] + :: a unique [=opaque origin=] + : [=request/credentials mode=] + :: "include" + + 1. [=Queue a global task=] on the [=network task source=] given |globalObject| + to [=fetch=] |fetchRequest|. + 1. Set the |accountState| {{AccountState/allows logout}} to false. + 1. Resolve |promise| with [undefined]. + 1. Return |promise|.
From c338f71bc190db6a99a829b11c537634078f4b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Tue, 10 Jan 2023 15:13:21 -0500 Subject: [PATCH 12/17] b --- spec/index.bs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 6b4b0eedc..951eec697 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1220,11 +1220,9 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu To create an IdentityCredential given an {{IdentityProviderConfig}} |provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}}. 1. Assert: These steps are running [=in parallel=]. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - set |check| to the result of [=check the well-known file=] with |provider|. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - set |config| to the result of [=fetch the config file=] with |provider|. - 1. Wait until |check| and |config| are set. + 1. Let |check| be the result of running [=check the well-known file=] with |provider|. + 1. Let |config| be the result of running [=fetch the config file=] with |provider|. + 1. Wait until |check| and |config| are both set. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to set |accountsList| to the result of [=fetch the accounts list=] with |config| and |provider|. 1. Wait until |accountsList| is set. @@ -1258,13 +1256,26 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} 1. Return |credential|.
+
+To queue url parser given a {{USVString}} |stringURL| |globalObject|, run the following +steps. This returns a {{URL}} or failure. + 1. Let |configURL| be null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to: + 1. Let |configURL| be the result of running [=url parser=] with |stringURL|. + Note: We queue a task since the [=url parser=] needs to be run within a task, not + [=in parallel=]. + 1. Wait until |configURL| is set. + 1. Return |configURL|. +
+
To check the well-known file given an {{IdentityProviderConfig}} |provider|, run the following steps. This returns a boolean. 1. Assert: These steps are running on the [=DOM manipulation task source=]. - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s + 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. - 1. If |configUrl| is failure, return false. + 1. Wait until |configUrl| is set. + 1. If |configURL| is failure, return false. 1. Let |rootUrl| be a new [=/URL=]. 1. Set |rootUrl|'s [=url/scheme=] to |configUrl|'s [=url/scheme=]. 1. Set |rootUrl|'s [=url/host=] to |configUrl|'s [=url/host=]'s [=host/registrable domain=]. From 1772153d37de1a501b3f04c6fd40d6685d1e8c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Tue, 10 Jan 2023 17:24:03 -0500 Subject: [PATCH 13/17] b --- spec/index.bs | 187 ++++++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 99 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 951eec697..0ccac593c 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1220,12 +1220,10 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu To create an IdentityCredential given an {{IdentityProviderConfig}} |provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}}. 1. Assert: These steps are running [=in parallel=]. - 1. Let |check| be the result of running [=check the well-known file=] with |provider|. - 1. Let |config| be the result of running [=fetch the config file=] with |provider|. - 1. Wait until |check| and |config| are both set. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - set |accountsList| to the result of [=fetch the accounts list=] with |config| and |provider|. - 1. Wait until |accountsList| is set. + 1. Let |config| be the result of running [=check the well-known file and fetch the config file=] + with |provider| and |globalObject|. + 1. Let |accountsList| be the result of [=fetch the accounts list=] with |config|, |provider|, + and |globalObject|. 1. If |accountsList|'s size is 1: 1. Let |account| be |accountsList|[0]. 1. Let |accountState| be the result of running the [=compute account state=] algorithm @@ -1249,39 +1247,53 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} 1. Wait until the [=user agent=]'s dialog is closed and |accountState| has been updated. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new "{{NetworkError}}" {{DOMException}}. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - set |credential| to the result of running [=create tokens=] algorithm with |accountState|, - |account|'s {{IdentityProviderAccount/id}}, |provider|, |config|, and |globalObject|. - 1. Wait until |credential| is set. + 1. Let |credential| be the result of running the [=create a credential=] algorithm with + |accountState|, |account|'s {{IdentityProviderAccount/id}}, |provider|, |config|, and + |globalObject|. 1. Return |credential|.
-To queue url parser given a {{USVString}} |stringURL| |globalObject|, run the following -steps. This returns a {{URL}} or failure. - 1. Let |configURL| be null. +To queue url parser given a {{USVString}} |stringUrl|, a |globalObject|, and an optional +|baseUrl| (default null), run the following steps. This returns a [=/URL=] or failure. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to: - 1. Let |configURL| be the result of running [=url parser=] with |stringURL|. + 1. Let |configUrl| be the result of running [=url parser=] with |stringUrl| and |baseUrl|. + Note: We queue a task since the [=url parser=] needs to be run within a task, not [=in parallel=]. - 1. Wait until |configURL| is set. - 1. Return |configURL|. + + 1. Wait for |configUrl| to be set. + 1. Return |configUrl|. +
+ +
+To queue fetch given a [=/request=] |request|, |globalObject|, and an algorithm +|processResponseConsumeBody|, run the following steps: + 1. [=Queue a global task=] on the [=network task source=] given |globalObject| to: + 1. [=Fetch=] |request| with processResponseConsumeBody set to + |processResponseConsumeBody|. + + Note: We queue a task since the [=fetch=] needs to be run within a task, not [=in parallel=].
-To check the well-known file given an {{IdentityProviderConfig}} |provider|, run the -following steps. This returns a boolean. - 1. Assert: These steps are running on the [=DOM manipulation task source=]. +To check the well-known file and fetch the config file given an +{{IdentityProviderConfig}} |provider| and |globalObject|, run the following steps. This returns an +{{IdentityProviderAPIConfig}}. 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. Wait until |configUrl| is set. - 1. If |configURL| is failure, return false. + {{IdentityProviderConfig/configURL}} and |globalObject|. + 1. If |configUrl| is failure, throw a "{{NetworkError}}" {{DOMException}}. + 1. Run a [[!CSP]] check with a [[CSP#directive-connect-src|connect-src]] directive on the URL + passed as |configUrl|. If it fails, throw a new "{{NetworkError}}" {{DOMException}}. + 1. If |configUrl| is not a [=potentially trustworthy URL=], throw a new "{{NetworkError}}" + {{DOMException}}. 1. Let |rootUrl| be a new [=/URL=]. 1. Set |rootUrl|'s [=url/scheme=] to |configUrl|'s [=url/scheme=]. 1. Set |rootUrl|'s [=url/host=] to |configUrl|'s [=url/host=]'s [=host/registrable domain=]. 1. Set |rootUrl|'s [=url/path=] to the list «".well-known", "web-identity"». - 1. If |rootUrl| is not a [=potentially trustworthy URL=], return false. - 1. Let |request| be a new request as follows: + 1. If |rootUrl| is not a [=potentially trustworthy URL=], throw a "{{NetworkError}}" + {{DOMException}}. + 1. Let |wellKnownRequest| be a new [=/request=] as follows: : [=request/URL=] :: |rootUrl| @@ -1307,13 +1319,12 @@ following steps. This returns a boolean. with [=request/mode=] set to "unsafe-no-cors". See the relevant [pull request](https://github.com/whatwg/fetch/pull/1533) for details.

- 1. Let |check| be null. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the - following steps given a response |response|: + 1. [=Queue fetch=] with |wellKnownRequest|, |globalObject|, and processResponseConsumeBody + set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, |discovery|. - 1. Set |check| as follows: + 1. Let |check| be set as follows: 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] is greater than 1, set |check| to false. @@ -1323,21 +1334,8 @@ following steps. This returns a boolean. 1. Otherwise, set |check| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. 1. If |check| is false, throw a "{{NetworkError}}" {{DOMException}}. - 1. [=In parallel=], wait until |check| becomes non-null, and return it. -
-
-To fetch the config file algorithm given an {{IdentityProviderConfig}} |provider|, -run the following steps. This returns an {{IdentityProviderAPIConfig}}: - 1. Assert: These steps are running on the [=DOM manipulation task source=]. - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. If |configUrl| is failure, throw a new "{{NetworkError}}" {{DOMException}}. - 1. Run a [[!CSP]] check with a [[CSP#directive-connect-src|connect-src]] - directive on the URL passed as |configUrl|. - 1. If |configUrl| is not a [=potentially trustworthy URL=], throw a new "{{NetworkError}}" - {{DOMException}}. - 1. Let |request| be a new request as follows: + 1. Let |configRequest| be a new request as follows: : [=request/url=] :: |configUrl| @@ -1361,13 +1359,14 @@ run the following steps. This returns an {{IdentityProviderAPIConfig}}: : [=request/credentials mode=] :: "omit" - 1. Let |config| be null. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: + 1. [=Queue fetch=] with |configRequest|, |globalObject|, and processResponseConsumeBody + set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}} stored in |config|. - 1. [=In parallel=], wait until |config| is not null, and return it. + 1. Wait for both |check| and |config| to be set. + 1. Assert: |check| (should have thrown an exception if it is false). + 1. Return |config|.
NOTE: We use a two-tier file system in order to prevent the [=IDP=] to easily determine the [=RP=] @@ -1380,11 +1379,10 @@ path manipulation to fingerprint (for instance, by including the RP in the path)
To fetch the accounts list given an {{IdentityProviderAPIConfig}} |config|, an -{{IdentityProviderConfig}} |provider|, run the following steps. This returns an +{{IdentityProviderConfig}} |provider|, and |globalObject|, run the following steps. This returns an {{IdentityProviderAccountList}}. - 1. Assert: These steps are running on the [=DOM manipulation task source=]. - 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider| and - |config|["{{IdentityProviderAPIConfig/accounts_endpoint}}"]. + 1. Let |accountsUrl| be the result of [=computing the manifest URL=] given |provider|, + |config|["{{IdentityProviderAPIConfig/accounts_endpoint}}"], and |globalObject|. 1. If |accountsUrl| is failure, return an empty list. 1. Let |request| be a new request as follows: @@ -1412,27 +1410,26 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |co Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). - 1. Let |accountsList| be null. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: + 1. [=Queue fetch=] with |request|, |globalObject|, and processResponseConsumeBody + set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, and store the result in |accountsList|. Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336). - 1. [=In parallel=], wait for |accountsList| to become non-null, and return it. + 1. Wait for |accountsList| to be set. + 1. Return |accountsList|.
-To create tokens given an [=AccountState=] |accountState|, a {{USVString}} |accountId|, - an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |config|, and - |globalObject|, run the following steps. This returns an {{IdentityCredential}}. - 1. Assert: These steps are running on the [=DOM manipulation task source=]. +To create a credential given an [=AccountState=] |accountState|, a {{USVString}} + |accountId|, an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} + |config|, and |globalObject|, run the following steps. This returns an {{IdentityCredential}}. 1. Assert |accountState|'s {{AccountState/registration state}} is [=registered=]. 1. Assert |accountState|'s {{AccountState/allows logout}} is true. - 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider| and - |config|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"]. + 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider|, + |config|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"], and |globalObject|. 1. If |idTokenUrl| is failure, throw a new "{{NetworkError}}" {{DOMException}}. 1. Let |requestBody| be a [=string=] resulting in concatenating "client_id=", |provider|'s {{IdentityProviderConfig/clientId}}, "&nonce=", @@ -1465,27 +1462,24 @@ To create tokens given an [=AccountState=] |accountState|, a {{USVStr : [=request/credentials mode=] :: "include" - 1. Let |credential| be null. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: + 1. [=Queue fetch=] with |request|, |globalObject|, and processResponseConsumeBody + set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |token|. 1. Let |credential| be a new {{IdentityCredential}} given |globalObject|'s realm. 1. Set |credential|'s {{IdentityCredential/token}} to |token|. - 1. [=In parallel=], wait for |credential| to be non-null, and return it. + 1. Wait for |credential| to be set. + 1. Return |credential|.
To compute account state given an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps. This returns an [=AccountState=]. - 1. Assert: These steps are running [=in parallel=]. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - compute |configUrl| as the result of running [=url parser=] with |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. Wait until |configUrl| is set, and let |idpOrigin| be the [=origin=] corresponding to - |configUrl|. + 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s + {{IdentityProviderConfig/configURL}} and |globalObject|. + 1. Let |idpOrigin| be the [=origin=] corresponding to |configUrl|. 1. Let |rpOrigin| be |globalObject|'s [=associated Document=]'s [=Document/origin=]. 1. Let |accountId| be |account|'s {{IdentityProviderAccount/id}}. 1. Let |triple| be (|rpOrigin|, |idpOrigin|, |accountId|). @@ -1496,15 +1490,16 @@ an [=AccountState=].
-When computing the manifest URL given an {{IdentityProviderConfig}} |provider| and a -[=string=] |manifestString|, perform the following steps. This returns a URL or -failure. - 1. Assert: These steps are running on the [=DOM manipulation task source=]. - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s - {{IdentityProviderConfig/configURL}}. - 1. Let |manifestUrl| be the result of running [=url parser=] given |manifestString|. - 1. If |manifestUrl| is failure, let |manifestUrl| be the result of running [=url parser=] given - |manifestString| (the relative URL) and |configUrl| (the base URL). +When computing the manifest URL given an {{IdentityProviderConfig}} |provider|, a +[=string=] |manifestString|, and |globalObject|, perform the following steps. This returns a +URL or failure. + 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s + {{IdentityProviderConfig/configURL}} and |globalObject|. + 1. Let |manifestUrl| be the result of running [=queue url parser=] given |manifestString| and + |globalObject|. + 1. If |manifestUrl| is failure, let |manifestUrl| be the result of running [=queue url parser=] + given |manifestString| (the relative URL), |globalObject|, and |configUrl| (the base URL). + Wait until |manifestUrl| is set again. Note: This means the we allow passing the manifest string as either an absolute or relative URL. @@ -1517,7 +1512,7 @@ failure.
To extract the JSON fetch response given a response |response|, run the following steps. This returns an [=ordered map=]. - 1. Assert: These steps are running on the [=DOM manipulation task source=]. + 1. Assert: These steps are running on the [=networking task source=]. 1. If |response| is a [=network error=] or its [=response/status=] is not an [=ok status=], throw a new "{{NetworkError}}" {{DOMException}}. 1. Let |mimeType| be the result of extracting a MIME TYPE from |response|'s @@ -1536,11 +1531,8 @@ To request permission to sign-up the user with a given an {{IdentityP [=AccountState=] |accountState|, an {{IdentityProviderAPIConfig}} |config|, an {{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps. This returns a boolean. 1. Assert: These steps are running [=in parallel=]. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to - [=fetch the client metadata=] algorithm with |config| and |provider|, and set the result to - |metadata|. - 1. Wait until |metadata| is set. - 1. Assert: |metadata| is null or an {{IdentityProviderClientMetadata}}. + 1. Let |metadata| be the result of running [=fetch the client metadata=] with |config|, + |provider|, and |globalObject|. 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of |account|["{{IdentityProviderAccount/approved_clients}}"], then display the @@ -1562,9 +1554,8 @@ To request permission to sign-up the user with a given an {{IdentityP To fetch the client metadata given an {{IdentityProviderAPIConfig}} |config| and an {{IdentityProviderConfig}} |provider|, run the following steps. This returns an {{IdentityProviderClientMetadata}}. - 1. Assert: These steps are running on the [=DOM manipulation task source=]. - 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider| and - |config|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"]. + 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider|, + |config|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"], and |globalObject|. 1. If |clientMetadataUrl| is failure, throw a new "{{NetworkError}}" {{DOMException}}. 1. Let |request| be a new request as follows: @@ -1590,19 +1581,18 @@ an {{IdentityProviderConfig}} |provider|, run the following steps. This returns : [=request/credentials mode=] :: "omit" - 1. Let |metadata| be null. - 1. [=Fetch=] |request| with processResponseConsumeBody set to the following - steps given a response |response|: + 1. [=Queue fetch=] with |request|, |globalObject|, and processResponseConsumeBody + set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, and store the result in |metadata|. - 1. [=In parallel=], wait until |metadata| becomes not null, and return it. + 1. Wait until |metadata| is set. + 1. Return |metadata|.
To select an account given an |accountsList|, run the following steps. This returns an {{IdentityProviderAccount}}. - 1. Assert: These steps are running [=in parallel=]. 1. Assert |accountsList|'s [=list/size=] is greater than 1. 1. Display an account chooser displaying the options from |accountsList|. 1. Let |account| be the {{IdentityProviderAccount}} of the account that the user @@ -1613,7 +1603,6 @@ To select an account given an |accountsList|, run the following steps
To sign-in the user with a given an [=AccountState=] |accountState|: - 1. Assert: These steps are running [=in parallel=]. 1. Assert that |accountState|'s {{AccountState/registration state}} is [=registered=] 1. Change |accountState|'s {{AccountState/allows logout}} from false to true.
@@ -2235,11 +2224,11 @@ IDPs are also offered an extension to the {{IdentityProviderAPIConfig}} object t The [=user agent=] uses the following [=maybe fetch the accounts list=] instead of the [=fetch the accounts list=] algorithm. It would also return early on if the user was {{Sign-in Status/signed-out}}.
-To maybe fetch the accounts list given an {{IdentityProviderAPIConfig}} |config| and an {{IdentityProviderConfig}} -|provider|, run the following steps. This returns a [=list=]. +To maybe fetch the accounts list given an {{IdentityProviderAPIConfig}} |config|, an {{IdentityProviderConfig}} +|provider|, and a |globalObject|, run the following steps. This returns a [=list=]. - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s - {{IdentityProviderConfig/configURL}}. + 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s + {{IdentityProviderConfig/configURL}} and |globalObject|. 1. Let |idpOrigin| be the origin corresponding to |configUrl|. 1. Let |status| be the [=Sign-in Status=] of the |idpOrigin|. 1. If |status| is {{Sign-in Status/unknown}}: @@ -2269,7 +2258,7 @@ To maybe fetch the accounts list given an {{IdentityProviderAPIConfig
To Sign-in to the IDP given an {{IdentityProviderAPIConfig}} |config| and an {{IdentityProviderConfig}} |provider|. This returns a [=list=]. - 1. Let |configUrl| be the result of running [=url parser=] with |provider|'s + 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. Let |idpOrigin| be the origin corresponding to |configUrl|. 1. Assert that the [=Sign-in Status=] of the |idpOrigin| is {{Sign-in Status/signed-out}}. From afd1d590d8e24c1458928f96fe47b5c267c44d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Thu, 12 Jan 2023 10:03:03 -0500 Subject: [PATCH 14/17] b --- spec/index.bs | 69 ++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 0ccac593c..a0a41b1a3 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1220,8 +1220,8 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu To create an IdentityCredential given an {{IdentityProviderConfig}} |provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}}. 1. Assert: These steps are running [=in parallel=]. - 1. Let |config| be the result of running [=check the well-known file and fetch the config file=] - with |provider| and |globalObject|. + 1. Let |config| be the result of running [=fetch the config file=] with |provider| and + |globalObject|. 1. Let |accountsList| be the result of [=fetch the accounts list=] with |config|, |provider|, and |globalObject|. 1. If |accountsList|'s size is 1: @@ -1229,8 +1229,8 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} 1. Let |accountState| be the result of running the [=compute account state=] algorithm given |provider|, |account|, and |globalObject|. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=], - [=request permission to sign-up=] algorithm with |account|, |accountState|, |config|, - |provider|, and |globalObject| and set the result in |permission|. + let |permission| be the result of running [=request permission to sign-up=] algorithm + with |account|, |accountState|, |config|, |provider|, and |globalObject|. 1. Otherwise, show a dialog to request user permission to sign in via |account|, and set the result in |permission|. 1. If |permission|, [=sign-in=] with |accountState|. @@ -1240,21 +1240,21 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} 1. Let |accountState| be the result of running the [=compute account state=] algorithm given |provider| and |account|. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=]: - 1. Run the [=request permission to sign-up=] algorithm with |account|, |accountState|, - |config|, |provider|, and |globalObject| and set the result in |permission|. + 1. Let |permission| be the result of running the [=request permission to sign-up=] + algorithm with |account|, |accountState|, |config|, |provider|, and |globalObject|. 1. If |permission|, [=sign-in=] with |accountState|. 1. Otherwise, [=sign-in=] with |accountState|. - 1. Wait until the [=user agent=]'s dialog is closed and |accountState| has been updated. + 1. Wait until the [=user agent=]'s dialog is closed. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new "{{NetworkError}}" {{DOMException}}. - 1. Let |credential| be the result of running the [=create a credential=] algorithm with + 1. Let |credential| be the result of running the [=fetch an identity assertion=] algorithm with |accountState|, |account|'s {{IdentityProviderAccount/id}}, |provider|, |config|, and |globalObject|. 1. Return |credential|.
-To queue url parser given a {{USVString}} |stringUrl|, a |globalObject|, and an optional +To parse url given a {{USVString}} |stringUrl|, a |globalObject|, and an optional |baseUrl| (default null), run the following steps. This returns a [=/URL=] or failure. 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to: 1. Let |configUrl| be the result of running [=url parser=] with |stringUrl| and |baseUrl|. @@ -1267,7 +1267,7 @@ To queue url parser given a {{USVString}} |stringUrl|, a |globalObjec
-To queue fetch given a [=/request=] |request|, |globalObject|, and an algorithm +To fetch request given a [=/request=] |request|, |globalObject|, and an algorithm |processResponseConsumeBody|, run the following steps: 1. [=Queue a global task=] on the [=network task source=] given |globalObject| to: 1. [=Fetch=] |request| with processResponseConsumeBody set to @@ -1277,10 +1277,9 @@ To queue fetch given a [=/request=] |request|, |globalObject|, and an
-To check the well-known file and fetch the config file given an -{{IdentityProviderConfig}} |provider| and |globalObject|, run the following steps. This returns an -{{IdentityProviderAPIConfig}}. - 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s +To fetch the config file given an {{IdentityProviderConfig}} |provider| and +|globalObject|, run the following steps. This returns an {{IdentityProviderAPIConfig}}. + 1. Let |configUrl| be the result of running [=parse url=] with |provider|'s {{IdentityProviderConfig/configURL}} and |globalObject|. 1. If |configUrl| is failure, throw a "{{NetworkError}}" {{DOMException}}. 1. Run a [[!CSP]] check with a [[CSP#directive-connect-src|connect-src]] directive on the URL @@ -1319,21 +1318,20 @@ To check the well-known file and fetch the config file given an with [=request/mode=] set to "unsafe-no-cors". See the relevant [pull request](https://github.com/whatwg/fetch/pull/1533) for details.

- 1. [=Queue fetch=] with |wellKnownRequest|, |globalObject|, and processResponseConsumeBody + 1. [=Fetch request=] with |wellKnownRequest|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, |discovery|. - 1. Let |check| be set as follows: - 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] - is greater than 1, set |check| to false. + 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] + is greater than 1, throw a new "{{NetworkError}}" {{DOMException}}. - Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the - provider_urls array. + Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the + provider_urls array. - 1. Otherwise, set |check| to |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] - [=string/is=] equal to |provider|'s {{IdentityProviderConfig/configURL}}. - 1. If |check| is false, throw a "{{NetworkError}}" {{DOMException}}. + 1. If |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] + [=string/is=] NOT equal to |provider|'s {{IdentityProviderConfig/configURL}}, throw a + "{{NetworkError}}" {{DOMException}}. 1. Let |configRequest| be a new request as follows: @@ -1359,13 +1357,12 @@ To check the well-known file and fetch the config file given an : [=request/credentials mode=] :: "omit" - 1. [=Queue fetch=] with |configRequest|, |globalObject|, and processResponseConsumeBody + 1. [=Fetch request=] with |configRequest|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}} stored in |config|. - 1. Wait for both |check| and |config| to be set. - 1. Assert: |check| (should have thrown an exception if it is false). + 1. Wait for both fetch responses to be completed. 1. Return |config|.
@@ -1410,7 +1407,7 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |co Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). - 1. [=Queue fetch=] with |request|, |globalObject|, and processResponseConsumeBody + 1. [=Fetch request=] with |request|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, and @@ -1423,7 +1420,7 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |co
-To create a credential given an [=AccountState=] |accountState|, a {{USVString}} +To fetch an identity assertion given an [=AccountState=] |accountState|, a {{USVString}} |accountId|, an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAPIConfig}} |config|, and |globalObject|, run the following steps. This returns an {{IdentityCredential}}. 1. Assert |accountState|'s {{AccountState/registration state}} is [=registered=]. @@ -1462,7 +1459,7 @@ To create a credential given an [=AccountState=] |accountState|, a {{ : [=request/credentials mode=] :: "include" - 1. [=Queue fetch=] with |request|, |globalObject|, and processResponseConsumeBody + 1. [=Fetch request=] with |request|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderToken}}, |token|. @@ -1477,7 +1474,7 @@ To create a credential given an [=AccountState=] |accountState|, a {{ To compute account state given an {{IdentityProviderConfig}} |provider|, an {{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps. This returns an [=AccountState=]. - 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s + 1. Let |configUrl| be the result of running [=parse url=] with |provider|'s {{IdentityProviderConfig/configURL}} and |globalObject|. 1. Let |idpOrigin| be the [=origin=] corresponding to |configUrl|. 1. Let |rpOrigin| be |globalObject|'s [=associated Document=]'s [=Document/origin=]. @@ -1493,11 +1490,11 @@ an [=AccountState=]. When computing the manifest URL given an {{IdentityProviderConfig}} |provider|, a [=string=] |manifestString|, and |globalObject|, perform the following steps. This returns a URL or failure. - 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s + 1. Let |configUrl| be the result of running [=parse url=] with |provider|'s {{IdentityProviderConfig/configURL}} and |globalObject|. - 1. Let |manifestUrl| be the result of running [=queue url parser=] given |manifestString| and + 1. Let |manifestUrl| be the result of running [=parse url=] given |manifestString| and |globalObject|. - 1. If |manifestUrl| is failure, let |manifestUrl| be the result of running [=queue url parser=] + 1. If |manifestUrl| is failure, let |manifestUrl| be the result of running [=parse url=] given |manifestString| (the relative URL), |globalObject|, and |configUrl| (the base URL). Wait until |manifestUrl| is set again. @@ -1581,7 +1578,7 @@ an {{IdentityProviderConfig}} |provider|, run the following steps. This returns : [=request/credentials mode=] :: "omit" - 1. [=Queue fetch=] with |request|, |globalObject|, and processResponseConsumeBody + 1. [=Fetch request=] with |request|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderClientMetadata}}, @@ -2227,7 +2224,7 @@ The [=user agent=] uses the following [=maybe fetch the accounts list=] instead To maybe fetch the accounts list given an {{IdentityProviderAPIConfig}} |config|, an {{IdentityProviderConfig}} |provider|, and a |globalObject|, run the following steps. This returns a [=list=]. - 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s + 1. Let |configUrl| be the result of running [=parse url=] with |provider|'s {{IdentityProviderConfig/configURL}} and |globalObject|. 1. Let |idpOrigin| be the origin corresponding to |configUrl|. 1. Let |status| be the [=Sign-in Status=] of the |idpOrigin|. @@ -2258,7 +2255,7 @@ To maybe fetch the accounts list given an {{IdentityProviderAPIConfig
To Sign-in to the IDP given an {{IdentityProviderAPIConfig}} |config| and an {{IdentityProviderConfig}} |provider|. This returns a [=list=]. - 1. Let |configUrl| be the result of running [=queue url parser=] with |provider|'s + 1. Let |configUrl| be the result of running [=parse url=] with |provider|'s {{IdentityProviderConfig/configURL}}. 1. Let |idpOrigin| be the origin corresponding to |configUrl|. 1. Assert that the [=Sign-in Status=] of the |idpOrigin| is {{Sign-in Status/signed-out}}. From c549b546c05117c47f363c24aceabe88b1ab7bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Thu, 12 Jan 2023 11:29:40 -0500 Subject: [PATCH 15/17] b --- spec/index.bs | 52 +++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index a0a41b1a3..83c6c01c1 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1209,19 +1209,24 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu method to throw an error. If there was no such timer, the developer could easily infer whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=]. 1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0]. - 1. Return the result of running [=create an IdentityCredential=] with |provider| and + 1. Let |credential| be the result of running [=create an IdentityCredential=] with |provider| and |globalObject|. Note: The |globalObject| is not currently passed onto the {{Credential/[[DiscoverFromExternalSource]]}} algorithm. See issue. + + 1. If |credential| is failure, [=queue a global task=] on the [=DOM manipulation task source=] + to throw a new "{{NetworkError}}" {{DOMException}}.
To create an IdentityCredential given an {{IdentityProviderConfig}} -|provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}}. +|provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}} or +failure. 1. Assert: These steps are running [=in parallel=]. 1. Let |config| be the result of running [=fetch the config file=] with |provider| and |globalObject|. + 1. If |config| is failure, return failure. 1. Let |accountsList| be the result of [=fetch the accounts list=] with |config|, |provider|, and |globalObject|. 1. If |accountsList|'s size is 1: @@ -1237,6 +1242,7 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} 1. Otherwise: 1. Let |account| be the result of running the [=select an account=] from the |accountsList|. + 1. If |account| is failure, return failure. 1. Let |accountState| be the result of running the [=compute account state=] algorithm given |provider| and |account|. 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=]: @@ -1245,8 +1251,8 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} 1. If |permission|, [=sign-in=] with |accountState|. 1. Otherwise, [=sign-in=] with |accountState|. 1. Wait until the [=user agent=]'s dialog is closed. - 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then throw a new - "{{NetworkError}}" {{DOMException}}. + 1. If |accountState|'s {{AccountState/registration state}} is [=unregistered=] then return + failure. 1. Let |credential| be the result of running the [=fetch an identity assertion=] algorithm with |accountState|, |account|'s {{IdentityProviderAccount/id}}, |provider|, |config|, and |globalObject|. @@ -1281,17 +1287,15 @@ To fetch the config file given an {{IdentityProviderConfig}} |provide |globalObject|, run the following steps. This returns an {{IdentityProviderAPIConfig}}. 1. Let |configUrl| be the result of running [=parse url=] with |provider|'s {{IdentityProviderConfig/configURL}} and |globalObject|. - 1. If |configUrl| is failure, throw a "{{NetworkError}}" {{DOMException}}. + 1. If |configUrl| is failure, return failure. 1. Run a [[!CSP]] check with a [[CSP#directive-connect-src|connect-src]] directive on the URL - passed as |configUrl|. If it fails, throw a new "{{NetworkError}}" {{DOMException}}. - 1. If |configUrl| is not a [=potentially trustworthy URL=], throw a new "{{NetworkError}}" - {{DOMException}}. + passed as |configUrl|. If it fails, return failure. + 1. If |configUrl| is not a [=potentially trustworthy URL=], return failure. 1. Let |rootUrl| be a new [=/URL=]. 1. Set |rootUrl|'s [=url/scheme=] to |configUrl|'s [=url/scheme=]. 1. Set |rootUrl|'s [=url/host=] to |configUrl|'s [=url/host=]'s [=host/registrable domain=]. 1. Set |rootUrl|'s [=url/path=] to the list «".well-known", "web-identity"». - 1. If |rootUrl| is not a [=potentially trustworthy URL=], throw a "{{NetworkError}}" - {{DOMException}}. + 1. If |rootUrl| is not a [=potentially trustworthy URL=], return failure. 1. Let |wellKnownRequest| be a new [=/request=] as follows: : [=request/URL=] @@ -1318,20 +1322,21 @@ To fetch the config file given an {{IdentityProviderConfig}} |provide with [=request/mode=] set to "unsafe-no-cors". See the relevant [pull request](https://github.com/whatwg/fetch/pull/1533) for details.

+ 1. Let |config| be null. 1. [=Fetch request=] with |wellKnownRequest|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderWellKnown}}, |discovery|. 1. If the [=list/size=] of |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] - is greater than 1, throw a new "{{NetworkError}}" {{DOMException}}. + is greater than 1, set |config| to failure. Issue: [relax](https://github.com/fedidcg/FedCM/issues/333) the size of the provider_urls array. 1. If |discovery|["{{IdentityProviderWellKnown/provider_urls}}"] - [=string/is=] NOT equal to |provider|'s {{IdentityProviderConfig/configURL}}, throw a - "{{NetworkError}}" {{DOMException}}. + [=string/is=] NOT equal to |provider|'s {{IdentityProviderConfig/configURL}}, set + |config| to failure. 1. Let |configRequest| be a new request as follows: @@ -1361,7 +1366,7 @@ To fetch the config file given an {{IdentityProviderConfig}} |provide set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAPIConfig}} stored - in |config|. + in |config|, unless |config| has been set to failure. 1. Wait for both fetch responses to be completed. 1. Return |config|.
@@ -1427,7 +1432,7 @@ To fetch an identity assertion given an [=AccountState=] |accountStat 1. Assert |accountState|'s {{AccountState/allows logout}} is true. 1. Let |idTokenUrl| be the result of [=computing the manifest URL=] given |provider|, |config|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"], and |globalObject|. - 1. If |idTokenUrl| is failure, throw a new "{{NetworkError}}" {{DOMException}}. + 1. If |idTokenUrl| is failure, return failure. 1. Let |requestBody| be a [=string=] resulting in concatenating "client_id=", |provider|'s {{IdentityProviderConfig/clientId}}, "&nonce=", |provider|'s {{IdentityProviderConfig/nonce}}, "&account_id=", and |accountId|. @@ -1530,12 +1535,12 @@ To request permission to sign-up the user with a given an {{IdentityP 1. Assert: These steps are running [=in parallel=]. 1. Let |metadata| be the result of running [=fetch the client metadata=] with |config|, |provider|, and |globalObject|. - 1. If |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] is defined and the |provider|'s - {{IdentityProviderConfig/clientId}} is not in the list of + 1. If |metadata| is not null, |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] + is defined and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of |account|["{{IdentityProviderAccount/approved_clients}}"], then display the |metadata|["{{IdentityProviderClientMetadata/privacy_policy_url}}"] link. - 1. If |metadata| is not null, |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] is defined, - and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of + 1. If |metadata| is not null, |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] + is defined, and the |provider|'s {{IdentityProviderConfig/clientId}} is not in the list of |account|["{{IdentityProviderAccount/approved_clients}}"], then display the |metadata|["{{IdentityProviderClientMetadata/terms_of_service_url}}"] link. 1. Prompt the user to gather explicit intent to create an account. The user agent MAY use the @@ -1550,10 +1555,10 @@ To request permission to sign-up the user with a given an {{IdentityP
To fetch the client metadata given an {{IdentityProviderAPIConfig}} |config| and an {{IdentityProviderConfig}} |provider|, run the following steps. This returns an -{{IdentityProviderClientMetadata}}. +{{IdentityProviderClientMetadata}} or null. 1. Let |clientMetadataUrl| be the result of [=computing the manifest URL=] given |provider|, |config|["{{IdentityProviderAPIConfig/client_metadata_endpoint}}"], and |globalObject|. - 1. If |clientMetadataUrl| is failure, throw a new "{{NetworkError}}" {{DOMException}}. + 1. If |clientMetadataUrl| is failure, return null. 1. Let |request| be a new request as follows: : [=request/url=] @@ -1589,12 +1594,11 @@ an {{IdentityProviderConfig}} |provider|, run the following steps. This returns
To select an account given an |accountsList|, run the following steps. This returns an -{{IdentityProviderAccount}}. +{{IdentityProviderAccount}} or failure. 1. Assert |accountsList|'s [=list/size=] is greater than 1. 1. Display an account chooser displaying the options from |accountsList|. 1. Let |account| be the {{IdentityProviderAccount}} of the account that the user - manually selects from the accounts chooser, or throw a new "{{NetworkError}}" - {{DOMException}} if no account is selected. + manually selects from the accounts chooser, or failure if no account is selected. 1. Return |account|.
From 62632a9781da82f7f30ba64cb440fd779528ae8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Thu, 12 Jan 2023 13:32:03 -0500 Subject: [PATCH 16/17] b --- spec/index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/index.bs b/spec/index.bs index 83c6c01c1..250f45a4c 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1411,7 +1411,6 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |co :: "include" Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). - 1. [=Fetch request=] with |request|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. From 080871e2beb0adb27e1b5517778aaf52739eea40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Thu, 12 Jan 2023 13:39:52 -0500 Subject: [PATCH 17/17] b --- spec/index.bs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 250f45a4c..bfcc2d391 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -1262,10 +1262,11 @@ failure.
To parse url given a {{USVString}} |stringUrl|, a |globalObject|, and an optional |baseUrl| (default null), run the following steps. This returns a [=/URL=] or failure. - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to: - 1. Let |configUrl| be the result of running [=url parser=] with |stringUrl| and |baseUrl|. + 1. Let |configUrl| be null. + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to set + |configUrl| to the result of running [=url parser=] with |stringUrl| and |baseUrl|. - Note: We queue a task since the [=url parser=] needs to be run within a task, not + Note: We queue a task since the [=url parser=] needs to be run within a task, not [=in parallel=]. 1. Wait for |configUrl| to be set. @@ -1410,14 +1411,19 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |co : [=request/credentials mode=] :: "include" - Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the user's identities before the user grants permission. This is an active area of investigation that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). + Issue: The credentialed fetch in this algorithm can lead to a timing attack that leaks the + user's identities before the user grants permission. This is an active area of investigation + that is being explored [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1089040953). + + 1. Let |accountsList| be null. 1. [=Fetch request=] with |request|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityProviderAccountList}}, and store the result in |accountsList|. - Issue: We should validate the accounts list returned here for repeated ids, as described [here](https://github.com/fedidcg/FedCM/issues/336). + Issue: We should validate the accounts list returned here for repeated ids, as described + [here](https://github.com/fedidcg/FedCM/issues/336). 1. Wait for |accountsList| to be set. 1. Return |accountsList|. @@ -1463,6 +1469,7 @@ To fetch an identity assertion given an [=AccountState=] |accountStat : [=request/credentials mode=] :: "include" + 1. Let |credential| be null. 1. [=Fetch request=] with |request|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|. @@ -1502,7 +1509,8 @@ When computing the manifest URL given an {{IdentityProviderConfig}} | given |manifestString| (the relative URL), |globalObject|, and |configUrl| (the base URL). Wait until |manifestUrl| is set again. - Note: This means the we allow passing the manifest string as either an absolute or relative URL. + Note: This means the we allow passing the manifest string as either an absolute or relative + URL. 1. If |manifestUrl| is failure, return failure. 1. If |manifestUrl| is not [=same origin=] with |configUrl|, return failure. @@ -1582,6 +1590,7 @@ an {{IdentityProviderConfig}} |provider|, run the following steps. This returns : [=request/credentials mode=] :: "omit" + 1. Let |metadata| be null. 1. [=Fetch request=] with |request|, |globalObject|, and processResponseConsumeBody set to the following steps given a response |response|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response|.