Skip to content

Commit

Permalink
[FedCM] Prototype User Info API behind a flag (2/3)
Browse files Browse the repository at this point in the history
User Info API can be used by IDPs to render personalized buttons. See
proposal at w3c-fedid/FedCM#382.

This patch:
 - Implement the proposal to return the requested user info.

Next:
 - Add metrics and console logs

This patch is built on top of crrev.com/c/4117510

Bug: 1304402
Change-Id: Iaee7a1b716b20182b56ebd484d3fecd03a31ba49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4175904
Reviewed-by: David Bokan <bokan@chromium.org>
Reviewed-by: Nicolás Peña <npm@chromium.org>
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
Commit-Queue: Yi Gu <yigu@chromium.org>
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1095226}
  • Loading branch information
yi-gu authored and chromium-wpt-export-bot committed Jan 20, 2023
1 parent 8b30abf commit 3e84e83
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 2 deletions.
53 changes: 52 additions & 1 deletion credential-management/fedcm-network-requests.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
<body>

<script type="module">
import {default_request_options,
import {alt_manifest_origin,
default_request_options,
default_alt_request_options,
fedcm_test,
select_manifest,
Expand All @@ -23,6 +24,16 @@
});
}

async function createIframeWithPermissionPolicyAndWaitForMessage(test, iframeUrl) {
const messageWatcher = new EventWatcher(test, window, "message");
let iframe = document.createElement("iframe");
iframe.src = iframeUrl;
iframe.allow = "identity-credentials-get";
document.body.appendChild(iframe);
const message = await messageWatcher.wait_for("message");
return message.data;
}

fedcm_test(async t => {
const cred = await navigator.credentials.get(default_request_options());
assert_equals(cred.token, "token");
Expand Down Expand Up @@ -189,4 +200,44 @@
assert_equals(query_sw_iframe2.contentDocument.body.textContent, "1");
}, 'Test that service worker cannot observe fetches performed by FedCM API');

fedcm_test(async t => {
const cred = await navigator.credentials.get(default_alt_request_options());
assert_equals(cred.token, "token");

const iframe_in_idp_scope = `${alt_manifest_origin}/\
credential-management/support/fedcm/userinfo-iframe.html`;
const message = await createIframeWithPermissionPolicyAndWaitForMessage(t, iframe_in_idp_scope);
assert_equals(message.result, "Pass");
assert_equals(message.numAccounts, 1);
assert_equals(message.firstAccountEmail, "john_doe@idp.example");
}, 'Test basic User InFo API flow');

fedcm_test(async t => {
const cred = await navigator.credentials.get(default_alt_request_options());
assert_equals(cred.token, "token");

const iframe_in_idp_scope = `support/fedcm/userinfo-iframe.html`;
const message = await createIframeWithPermissionPolicyAndWaitForMessage(t, iframe_in_idp_scope);
assert_equals(message.result, "Fail");
}, 'Test that User Info API only works when invoked from iframe that is same origin as the IDP');

fedcm_test(async t => {
const cred = await navigator.credentials.get(default_alt_request_options());
assert_equals(cred.token, "token");

try {
const manifest_path = `${alt_manifest_origin}/\
credential-management/support/fedcm/manifest.py`;
const user_info = await IdentityProvider.getUserInfo({
configURL: manifest_path,
// Approved client
clientId: '123',
});
assert_unreached("Failure message");
} catch (error) {
assert_equals(error.message, "UserInfo request must be initiated from a frame that is the same origin with the provider.");
// Expect failure
}
}, 'Test that User Info API does not work in the top frame');

</script>
2 changes: 1 addition & 1 deletion credential-management/support/fedcm-helper.sub.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const alt_manifest_origin = 'https://{{hosts[alt][]}}:{{ports[https][0]}}';
export const alt_manifest_origin = 'https://{{hosts[alt][]}}:{{ports[https][0]}}';

// Set the identity provider cookie.
export function set_fedcm_cookie(host) {
Expand Down
10 changes: 10 additions & 0 deletions credential-management/support/fedcm-mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ export class MockFederatedAuthRequest {
this.pendingPromiseResolve_ = null;
}

// Implements
// RequestUserInfo(IdentityProviderGetParameters idp_get_param) =>
// (RequestUserInfoStatus status, array<IdentityUserInfo>? user_info);
async requestUserInfo(idp_get_param) {
return Promise.resolve({
status: "",
user_info: ""
});
}

async logoutRps(logout_endpoints) {
return Promise.resolve({
status: this.logoutRpsStatus_
Expand Down
34 changes: 34 additions & 0 deletions credential-management/support/fedcm/userinfo-iframe.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!doctype html>
<script type="module">
import {alt_manifest_origin} from './../fedcm-helper.sub.js';

// Loading fedcm-iframe.html in the test will make a FedCM call on load, and
// trigger a postMessage upon completion.
//
// message {
// string result: "Pass" | "Fail"
// string token: token.token
// string errorType: error.name
// }
window.onload = async () => {
try {
const manifest_path = `${alt_manifest_origin}/\
credential-management/support/fedcm/manifest.py`;
const user_info = await IdentityProvider.getUserInfo({
configURL: manifest_path,
// Approved client
clientId: '123',
});
let results = {
result: "Pass",
numAccounts: user_info.length,
firstAccountEmail: user_info[0].email
};
window.top.postMessage(results, '*');
} catch (error) {
window.top.postMessage({result: "Fail", errorType: error.name}, '*');
}
};

</script>

0 comments on commit 3e84e83

Please sign in to comment.