Skip to content

Commit a9ef96e

Browse files
cbiesingerdiemol
andauthored
Add support for FedCM commands (#12096)
* Add support for FedCM commands As specified in: https://fedidcg.github.io/FedCM/#automation Currently implemented in Chromium. * Fix some minor style issues --------- Co-authored-by: Diego Molina <diemol@users.noreply.github.com>
1 parent 6f58fb9 commit a9ef96e

18 files changed

+668
-0
lines changed

common/src/web/fedcm/accounts.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"accounts": [{
3+
"id": "1234",
4+
"given_name": "John",
5+
"name": "John Doe",
6+
"email": "john_doe@idp.example",
7+
"picture": "https://idp.example/profile/123",
8+
"approved_clients": ["123", "456", "789"]
9+
}, {
10+
"id": "5678",
11+
"given_name": "Aisha",
12+
"name": "Aisha Ahmad",
13+
"email": "aisha@idp.example",
14+
"picture": "https://idp.example/profile/567",
15+
"approved_clients": []
16+
}]
17+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"privacy_policy_url": "https://rp.example/privacy_policy.html",
3+
"terms_of_service_url": "https://rp.example/terms_of_service.html"
4+
}

common/src/web/fedcm/fedcm.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html>
2+
<script>
3+
4+
let configURL = `https://${location.host}/fedcm/fedcm.json`;
5+
let promise = null;
6+
7+
function triggerFedCm() {
8+
console.log(configURL);
9+
promise = navigator.credentials.get({
10+
identity: {
11+
providers: [{
12+
configURL: configURL,
13+
clientId: '1',
14+
}]
15+
}
16+
});
17+
return promise;
18+
}
19+
20+
</script>

common/src/web/fedcm/fedcm.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"accounts_endpoint": "accounts.json",
3+
"client_metadata_endpoint": "client_metadata.json",
4+
"id_assertion_endpoint": "id_assertion",
5+
"signin_url": "/signin"
6+
}

java/src/org/openqa/selenium/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ java_export(
1212
name = "core",
1313
srcs = glob([
1414
"*.java",
15+
"federatedcredentialmanagement/*.java",
1516
"html5/*.java",
1617
"internal/*.java",
1718
"interactions/**/*.java",
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.federatedcredentialmanagement;
19+
20+
import java.util.Map;
21+
22+
/**
23+
* Represents an account displayed in a FedCM account list.
24+
*
25+
* @see <a href="https://fedidcg.github.io/FedCM/#dictdef-identityprovideraccount">
26+
* https://fedidcg.github.io/FedCM/#dictdef-identityprovideraccount</a>
27+
* @see <a href="https://fedidcg.github.io/FedCM/#webdriver-accountlist">
28+
* https://fedidcg.github.io/FedCM/#webdriver-accountlist</a>
29+
*/
30+
public class FederatedCredentialManagementAccount {
31+
private final String accountId;
32+
private final String email;
33+
private final String name;
34+
private final String givenName;
35+
private final String pictureUrl;
36+
/**
37+
* The config URL of the identity provider that provided this account.
38+
*
39+
* This allows identifying the IDP in multi-IDP cases.
40+
*/
41+
private final String idpConfigUrl;
42+
/**
43+
* The login state for this account.
44+
*
45+
* One of LOGIN_STATE_SIGNIN and LOGIN_STATE_SIGNUP.
46+
*/
47+
private final String loginState;
48+
private final String termsOfServiceUrl;
49+
private final String privacyPolicyUrl;
50+
51+
public static final String LOGIN_STATE_SIGNIN = "SignIn";
52+
public static final String LOGIN_STATE_SIGNUP = "SignUp";
53+
54+
public FederatedCredentialManagementAccount(Map<String, String> dict) {
55+
accountId = (String) dict.getOrDefault("accountId", null);
56+
email = (String) dict.getOrDefault("email", null);
57+
name = (String) dict.getOrDefault("name", null);
58+
givenName = (String) dict.getOrDefault("givenName", null);
59+
pictureUrl = (String) dict.getOrDefault("pictureUrl", null);
60+
idpConfigUrl = (String) dict.getOrDefault("idpConfigUrl", null);
61+
loginState = (String) dict.getOrDefault("loginState", null);
62+
termsOfServiceUrl = (String) dict.getOrDefault("termsOfServiceUrl", null);
63+
privacyPolicyUrl = (String) dict.getOrDefault("privacyPolicyUrl", null);
64+
}
65+
66+
public String getAccountid() {
67+
return accountId;
68+
}
69+
70+
public String getEmail() {
71+
return email;
72+
}
73+
74+
public String getName() {
75+
return name;
76+
}
77+
78+
public String getGivenName() {
79+
return givenName;
80+
}
81+
82+
public String getPictureUrl() {
83+
return pictureUrl;
84+
}
85+
86+
public String getIdpConfigUrl() {
87+
return idpConfigUrl;
88+
}
89+
90+
public String getLoginState() {
91+
return loginState;
92+
}
93+
94+
public String getTermsOfServiceUrl() {
95+
return termsOfServiceUrl;
96+
}
97+
98+
public String getPrivacyPolicyUrl() {
99+
return privacyPolicyUrl;
100+
}
101+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.federatedcredentialmanagement;
19+
20+
import java.util.List;
21+
22+
/**
23+
* Represents an open dialog of the Federated Credential Management API.
24+
*
25+
* @see <a href="https://fedidcg.github.io/FedCM/">https://fedidcg.github.io/FedCM/</a>
26+
*/
27+
public interface FederatedCredentialManagementDialog {
28+
29+
String DIALOG_TYPE_ACCOUNT_LIST = "AccountChooser";
30+
String DIALOG_TYPE_AUTO_REAUTH = "AutoReauthn";
31+
32+
/**
33+
* Closes the dialog as if the user had clicked X.
34+
*/
35+
void cancelDialog();
36+
37+
/**
38+
* Selects an account as if the user had clicked on it.
39+
*
40+
* @param index The index of the account to select from the list
41+
* returned by getAccounts().
42+
*/
43+
void selectAccount(int index);
44+
45+
/**
46+
* Returns the type of the open dialog.
47+
*
48+
* One of DIALOG_TYPE_ACCOUNT_LIST and DIALOG_TYPE_AUTO_REAUTH.
49+
*/
50+
String getDialogType();
51+
52+
/**
53+
* Returns the title of the dialog.
54+
*/
55+
String getTitle();
56+
57+
/**
58+
* Returns the subtitle of the dialog or null if none.
59+
*/
60+
String getSubtitle();
61+
62+
/**
63+
* Returns the accounts shown in the account chooser.
64+
*
65+
* If this is an auto reauth dialog, returns the single account
66+
* that is being signed in.
67+
*/
68+
List<FederatedCredentialManagementAccount> getAccounts();
69+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.federatedcredentialmanagement;
19+
20+
import org.openqa.selenium.Beta;
21+
22+
/**
23+
* Used by classes to indicate that they can interact with FedCM dialogs.
24+
*/
25+
@Beta
26+
public interface HasFederatedCredentialManagement {
27+
/**
28+
* Disables the promise rejection delay.
29+
*
30+
* FedCM by default delays promise resolution in failure cases for privacy
31+
* reasons (https://fedidcg.github.io/FedCM/#ref-for-setdelayenabled);
32+
* this function allows turning it off to let tests run faster where this
33+
* is not relevant.
34+
*/
35+
void setDelayEnabled(boolean enabled);
36+
37+
/**
38+
* Resets the FedCM dialog cooldown.
39+
*
40+
* If a user agent triggers a cooldown when the account chooser is dismissed,
41+
* this function resets that cooldown so that the dialog can be triggered
42+
* again immediately.
43+
*/
44+
void resetCooldown();
45+
46+
/**
47+
* Gets the currently open FedCM dialog, or null if there is no dialog.
48+
*
49+
* Can be used with WebDriverWait like:
50+
* wait.until(driver -> ((HasFederatedCredentialManagement) driver).
51+
* getFederatedCredentialManagementDialog() != null);
52+
*/
53+
FederatedCredentialManagementDialog getFederatedCredentialManagementDialog();
54+
}
55+

java/src/org/openqa/selenium/grid/web/ResourceHandler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static com.google.common.net.MediaType.GIF;
2323
import static com.google.common.net.MediaType.HTML_UTF_8;
2424
import static com.google.common.net.MediaType.JAVASCRIPT_UTF_8;
25+
import static com.google.common.net.MediaType.JSON_UTF_8;
2526
import static com.google.common.net.MediaType.JPEG;
2627
import static com.google.common.net.MediaType.OCTET_STREAM;
2728
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
@@ -160,6 +161,10 @@ private String mediaType(String uri) {
160161
type = JAVASCRIPT_UTF_8;
161162
break;
162163

164+
case "json":
165+
type = JSON_UTF_8;
166+
break;
167+
163168
case "md":
164169
case "txt":
165170
type = PLAIN_TEXT_UTF_8;

java/src/org/openqa/selenium/remote/DriverCommand.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ public interface DriverCommand {
162162
String REMOVE_CREDENTIAL = "removeCredential";
163163
String REMOVE_ALL_CREDENTIALS = "removeAllCredentials";
164164
String SET_USER_VERIFIED = "setUserVerified";
165+
// Federated Credential Management API
166+
// https://fedidcg.github.io/FedCM/#automation
167+
String CANCEL_DIALOG = "cancelDialog";
168+
String SELECT_ACCOUNT = "selectAccount";
169+
String GET_ACCOUNTS = "getAccounts";
170+
String GET_FEDCM_TITLE = "getFedCmTitle";
171+
String GET_FEDCM_DIALOG_TYPE = "getFedCmDialogType";
172+
String SET_DELAY_ENABLED = "setDelayEnabled";
173+
String RESET_COOLDOWN = "resetCooldown";
165174

166175
static CommandPayload NEW_SESSION(Capabilities capabilities) {
167176
Require.nonNull("Capabilities", capabilities);
@@ -401,4 +410,14 @@ static CommandPayload SET_CURRENT_WINDOW_SIZE(Dimension targetSize) {
401410
SET_CURRENT_WINDOW_SIZE,
402411
ImmutableMap.of("width", targetSize.width, "height", targetSize.height));
403412
}
413+
414+
static CommandPayload SELECT_ACCOUNT(int index) {
415+
return new CommandPayload(
416+
SELECT_ACCOUNT, ImmutableMap.of("accountIndex", index));
417+
}
418+
419+
static CommandPayload SET_DELAY_ENABLED(boolean enabled) {
420+
return new CommandPayload(
421+
SET_DELAY_ENABLED, ImmutableMap.of("enabled", enabled));
422+
}
404423
}

0 commit comments

Comments
 (0)