0

[FedCM] Implement auto sign-in cooldown

When a user is auto signed-in and logs out to switch the account being
used, they might run into a deadloop where they are auto signed-in into
the same account again. We add a 10 minute cooldown which starts from
the time a user is auto signed-in. Within the cooldown, the user will be
able to sign-in explicitly through choosing an account on the dialog.
The cooldown time will be subject to change as we have yet to gather
metrics to validate if 10 minutes is ideal.

Bug: 1408533
Change-Id: Ic3323d5f638cc0c21124b6561131b8b874350639
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4216231
Reviewed-by: Dominick Ng <dominickn@chromium.org>
Reviewed-by: Alexander Timin <altimin@chromium.org>
Reviewed-by: Yi Gu <yigu@chromium.org>
Commit-Queue: Zachary Tan <tanzachary@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1103248}
This commit is contained in:
Zachary Tan
2023-02-09 13:53:36 +00:00
committed by Chromium LUCI CQ
parent 2119018fbb
commit 11b28b1c63
19 changed files with 277 additions and 30 deletions

@ -5,19 +5,44 @@
#include "chrome/browser/webid/federated_identity_auto_signin_permission_context.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/permissions/permission_decision_auto_blocker.h"
#include "url/origin.h"
FederatedIdentityAutoSigninPermissionContext::
FederatedIdentityAutoSigninPermissionContext(
content::BrowserContext* browser_context)
: host_content_settings_map_(
HostContentSettingsMapFactory::GetForProfile(browser_context)) {}
HostContentSettingsMapFactory::GetForProfile(browser_context)),
permission_autoblocker_(
PermissionDecisionAutoBlockerFactory::GetForProfile(
Profile::FromBrowserContext(browser_context))) {}
FederatedIdentityAutoSigninPermissionContext::
~FederatedIdentityAutoSigninPermissionContext() = default;
bool FederatedIdentityAutoSigninPermissionContext::HasAutoSigninPermission() {
return host_content_settings_map_->GetDefaultContentSetting(
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION,
/*provider_id=*/nullptr) != ContentSetting::CONTENT_SETTING_BLOCK;
bool FederatedIdentityAutoSigninPermissionContext::HasAutoSigninPermission(
const url::Origin& relying_party_embedder) {
bool is_content_setting_allowed =
host_content_settings_map_->GetDefaultContentSetting(
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION,
/*provider_id=*/nullptr) != ContentSetting::CONTENT_SETTING_BLOCK;
bool is_embargoed = permission_autoblocker_->IsEmbargoed(
relying_party_embedder.GetURL(),
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION);
return is_content_setting_allowed && !is_embargoed;
}
void FederatedIdentityAutoSigninPermissionContext::RecordDisplayAndEmbargo(
const url::Origin& relying_party_embedder) {
const GURL rp_embedder_url = relying_party_embedder.GetURL();
host_content_settings_map_->SetContentSettingDefaultScope(
rp_embedder_url, rp_embedder_url,
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION,
CONTENT_SETTING_BLOCK);
permission_autoblocker_->RecordDisplayAndEmbargo(
rp_embedder_url,
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION);
}

@ -13,6 +13,10 @@ namespace content {
class BrowserContext;
}
namespace permissions {
class PermissionDecisionAutoBlocker;
}
// Context for storing user permission to use the browser FedCM API's auto
// sign-in feature.
class FederatedIdentityAutoSigninPermissionContext
@ -30,10 +34,15 @@ class FederatedIdentityAutoSigninPermissionContext
const FederatedIdentityAutoSigninPermissionContext&) = delete;
// content::FederatedIdentityAutoSigninPermissionContextDelegate:
bool HasAutoSigninPermission() override;
bool HasAutoSigninPermission(
const url::Origin& relying_party_embedder) override;
void RecordDisplayAndEmbargo(
const url::Origin& relying_party_embedder) override;
private:
const raw_ptr<HostContentSettingsMap> host_content_settings_map_;
const raw_ptr<permissions::PermissionDecisionAutoBlocker, DanglingUntriaged>
permission_autoblocker_;
};
#endif // CHROME_BROWSER_WEBID_FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION_CONTEXT_H_

@ -11,6 +11,8 @@
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
class FederatedIdentityAutoSigninPermissionContextTest : public testing::Test {
public:
@ -35,10 +37,10 @@ class FederatedIdentityAutoSigninPermissionContextTest : public testing::Test {
base::raw_ptr<FederatedIdentityAutoSigninPermissionContext> context_;
base::raw_ptr<HostContentSettingsMap> host_content_settings_map_;
ContentSetting GetContentSetting() {
return host_content_settings_map_->GetDefaultContentSetting(
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION,
nullptr);
ContentSetting GetContentSetting(const GURL& rp_url) {
return host_content_settings_map_->GetContentSetting(
rp_url, rp_url,
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION);
}
private:
@ -49,5 +51,22 @@ class FederatedIdentityAutoSigninPermissionContextTest : public testing::Test {
// Test that FedCM auto sign-in is opt-in by default.
TEST_F(FederatedIdentityAutoSigninPermissionContextTest,
AutoSigninEnabledByDefault) {
EXPECT_EQ(true, context_->HasAutoSigninPermission());
GURL rp_url("https://rp.com");
EXPECT_EQ(true,
context_->HasAutoSigninPermission(url::Origin::Create(rp_url)));
}
// Test that
// FederatedIdentityAutoSigninPermissionContext::RecordDisplayAndEmbargo()
// blocks the permission if it is enabled.
TEST_F(FederatedIdentityAutoSigninPermissionContextTest, EnabledEmbargo) {
GURL rp_url("https://rp.com");
host_content_settings_map_->SetDefaultContentSetting(
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION,
CONTENT_SETTING_ALLOW);
EXPECT_EQ(CONTENT_SETTING_ALLOW, GetContentSetting(rp_url));
// Embargoing `rp_url` should block the content setting for `rp_url`.
context_->RecordDisplayAndEmbargo(url::Origin::Create(rp_url));
EXPECT_EQ(CONTENT_SETTING_BLOCK, GetContentSetting(rp_url));
}

@ -20,6 +20,12 @@ BASE_FEATURE(kBlockPromptsIfIgnoredOften,
"BlockPromptsIfIgnoredOften",
base::FEATURE_ENABLED_BY_DEFAULT);
// Once the user has auto signed-in, automatically block subsequent auto sign-in
// prompts within the next 10 minutes.
BASE_FEATURE(kBlockRepeatedAutoSigninPrompts,
"BlockRepeatedAutoSigninPrompts",
base::FEATURE_ENABLED_BY_DEFAULT);
// Once the user declines a notification permission prompt in a WebContents,
// automatically dismiss subsequent prompts in the same WebContents, from any
// origin, until the next user-initiated navigation.

@ -19,6 +19,9 @@ BASE_DECLARE_FEATURE(kBlockPromptsIfDismissedOften);
COMPONENT_EXPORT(PERMISSIONS_COMMON)
BASE_DECLARE_FEATURE(kBlockPromptsIfIgnoredOften);
COMPONENT_EXPORT(PERMISSIONS_COMMON)
BASE_DECLARE_FEATURE(kBlockRepeatedAutoSigninPrompts);
COMPONENT_EXPORT(PERMISSIONS_COMMON)
BASE_DECLARE_FEATURE(kBlockRepeatedNotificationPermissionPrompts);

@ -75,6 +75,10 @@ const char kPermissionBlockedRepeatedIgnoresMessage[] =
"information.";
#endif
const char kPermissionBlockedRecentDisplayMessage[] =
"%s permission has been blocked as the prompt has already been displayed "
"to the user recently.";
const char kPermissionBlockedPermissionsPolicyMessage[] =
"%s permission has been blocked because of a permissions policy applied to"
" the current document. See https://goo.gl/EuHzyv for more details.";
@ -177,6 +181,10 @@ void PermissionContextBase::RequestPermission(
kPermissionBlockedPermissionsPolicyMessage,
content_settings_type_);
break;
case PermissionStatusSource::RECENT_DISPLAY:
LogPermissionBlockedMessage(rfh, kPermissionBlockedRecentDisplayMessage,
content_settings_type_);
break;
case PermissionStatusSource::PORTAL:
case PermissionStatusSource::FENCED_FRAME:
case PermissionStatusSource::INSECURE_ORIGIN:

@ -41,6 +41,12 @@ constexpr base::TimeDelta kFederatedIdentityApiEmbargoDurationDismiss[] = {
base::Hours(2) /* 1st dismissal */, base::Days(1) /* 2nd dismissal */,
base::Days(7), base::Days(28)};
// The duration that an origin will stay under embargo for the
// FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION permission due to an auto sign-in
// prompt being displayed recently.
constexpr base::TimeDelta kFederatedIdentityAutoSigninEmbargoDuration =
base::Minutes(10);
// The number of times that users may explicitly dismiss a permission prompt
// from an origin before it is automatically blocked.
int g_dismissals_before_block = kDefaultDismissalsBeforeBlock;
@ -70,6 +76,12 @@ int g_ignore_embargo_days = kDefaultEmbargoDays;
std::string GetStringForContentType(ContentSettingsType content_type) {
if (content_type == ContentSettingsType::FEDERATED_IDENTITY_API)
return "FederatedIdentityApi";
if (content_type ==
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION) {
return "FederatedIdentityAutoSignin";
}
return PermissionUtil::GetPermissionString(content_type);
}
@ -144,6 +156,12 @@ base::TimeDelta GetEmbargoDurationForContentSettingsType(
std::size(kFederatedIdentityApiEmbargoDurationDismiss) - 1));
return kFederatedIdentityApiEmbargoDurationDismiss[duration_index];
}
if (permission ==
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION) {
return kFederatedIdentityAutoSigninEmbargoDuration;
}
return base::Days(g_dismissal_embargo_days);
}
@ -207,11 +225,17 @@ const char PermissionDecisionAutoBlocker::kPermissionDismissalEmbargoKey[] =
const char PermissionDecisionAutoBlocker::kPermissionIgnoreEmbargoKey[] =
"ignore_embargo_days";
// static
const char PermissionDecisionAutoBlocker::kPermissionDisplayEmbargoKey[] =
"display_embargo_minutes";
// static
bool PermissionDecisionAutoBlocker::IsEnabledForContentSetting(
ContentSettingsType content_setting) {
return PermissionUtil::IsPermission(content_setting) ||
content_setting == ContentSettingsType::FEDERATED_IDENTITY_API;
content_setting == ContentSettingsType::FEDERATED_IDENTITY_API ||
content_setting ==
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION;
}
// static
@ -246,6 +270,14 @@ PermissionDecisionAutoBlocker::GetEmbargoResult(
PermissionStatusSource::MULTIPLE_IGNORES);
}
if (IsUnderEmbargo(permission_dict, features::kBlockRepeatedAutoSigninPrompts,
kPermissionDisplayEmbargoKey, current_time,
GetEmbargoDurationForContentSettingsType(
permission, /*dismiss_count=*/0))) {
return PermissionResult(CONTENT_SETTING_BLOCK,
PermissionStatusSource::RECENT_DISPLAY);
}
return absl::nullopt;
}
@ -444,6 +476,18 @@ bool PermissionDecisionAutoBlocker::RecordIgnoreAndEmbargo(
return false;
}
bool PermissionDecisionAutoBlocker::RecordDisplayAndEmbargo(
const GURL& url,
ContentSettingsType permission) {
DCHECK_EQ(permission,
ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION);
if (base::FeatureList::IsEnabled(features::kBlockRepeatedAutoSigninPrompts)) {
PlaceUnderEmbargo(url, permission, kPermissionDisplayEmbargoKey);
return true;
}
return false;
}
void PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts(
const GURL& url,
ContentSettingsType permission) {

@ -129,6 +129,11 @@ class PermissionDecisionAutoBlocker : public KeyedService {
ContentSettingsType permission,
bool ignored_prompt_was_quiet);
// Records that a prompt was displayed for |permission|. If
// features::kBlockRepeatedAutoSigninPrompts is enabled, it will place |url|
// under embargo for |permission|.
bool RecordDisplayAndEmbargo(const GURL& url, ContentSettingsType permission);
// Clears any existing embargo status for |url|, |permission|. For
// permissions embargoed under repeated dismissals, this means a prompt will
// be shown to the user on next permission request. Clears dismiss and
@ -171,6 +176,7 @@ class PermissionDecisionAutoBlocker : public KeyedService {
static const char kPromptIgnoreCountWithQuietUiKey[];
static const char kPermissionDismissalEmbargoKey[];
static const char kPermissionIgnoreEmbargoKey[];
static const char kPermissionDisplayEmbargoKey[];
raw_ptr<HostContentSettingsMap> settings_map_;

@ -823,6 +823,27 @@ void CheckFederatedIdentityApiEmbargoLiftedAfterTimeElapsing(
EXPECT_FALSE(result.has_value());
}
// Checks that embargo on federated identity auto sign-in permission is lifted
// only after the passed-in |time_delta| has elapsed.
void CheckFederatedIdentityAutoSigninEmbargoLiftedAfterTimeElapsing(
PermissionDecisionAutoBlocker* autoblocker,
base::SimpleTestClock* clock,
const GURL& url,
base::TimeDelta time_delta) {
ASSERT_LT(base::Minutes(1), time_delta);
clock->Advance(time_delta - base::Minutes(1));
absl::optional<PermissionResult> result = autoblocker->GetEmbargoResult(
url, ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION);
EXPECT_EQ(CONTENT_SETTING_BLOCK, result->content_setting);
EXPECT_EQ(PermissionStatusSource::RECENT_DISPLAY, result->source);
clock->Advance(base::Minutes(2));
result = autoblocker->GetEmbargoResult(
url, ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION);
EXPECT_FALSE(result.has_value());
}
} // namespace
TEST_F(PermissionDecisionAutoBlockerUnitTest,
@ -877,6 +898,22 @@ TEST_F(PermissionDecisionAutoBlockerUnitTest,
autoblocker(), clock(), url, base::Hours(2));
}
TEST_F(PermissionDecisionAutoBlockerUnitTest,
TestLogoutFederatedIdentityAutoSigninBackoff) {
GURL url("https://www.google.com");
clock()->SetNow(base::Time::Now());
absl::optional<PermissionResult> result = autoblocker()->GetEmbargoResult(
url, ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION);
EXPECT_FALSE(result.has_value());
// 10 minute embargo
EXPECT_TRUE(autoblocker()->RecordDisplayAndEmbargo(
url, ContentSettingsType::FEDERATED_IDENTITY_AUTO_SIGNIN_PERMISSION));
CheckFederatedIdentityAutoSigninEmbargoLiftedAfterTimeElapsing(
autoblocker(), clock(), url, base::Minutes(10));
}
TEST_F(PermissionDecisionAutoBlockerUnitTest,
ObserverIsNotifiedWhenEmbargoStarts) {
GURL url("https://www.google.com");

@ -45,6 +45,10 @@ enum class PermissionStatusSource {
// The status is the result of a permission being requested inside a fenced
// frame. Permissions are currently always denied inside a fenced frame.
FENCED_FRAME,
// The status is the result of being blocked due to having recently displayed
// the prompt to the user.
RECENT_DISPLAY,
};
struct PermissionResult {

@ -486,6 +486,10 @@ void PermissionUmaUtil::RecordEmbargoPromptSuppressionFromSource(
PermissionUmaUtil::RecordEmbargoPromptSuppression(
PermissionEmbargoStatus::REPEATED_IGNORES);
break;
case PermissionStatusSource::RECENT_DISPLAY:
PermissionUmaUtil::RecordEmbargoPromptSuppression(
PermissionEmbargoStatus::RECENT_DISPLAY);
break;
case PermissionStatusSource::UNSPECIFIED:
case PermissionStatusSource::KILL_SWITCH:
case PermissionStatusSource::INSECURE_ORIGIN:

@ -119,6 +119,7 @@ enum class PermissionEmbargoStatus {
// Removed: PERMISSIONS_BLACKLISTING = 1,
REPEATED_DISMISSALS = 2,
REPEATED_IGNORES = 3,
RECENT_DISPLAY = 4,
// Keep this at the end.
NUM,

@ -919,7 +919,8 @@ void FederatedAuthRequestImpl::MaybeShowAccountsDialog() {
bool maybe_proceed_with_auto_signin =
prefer_auto_signin && IsFedCmAutoReauthnEnabled() &&
auto_signin_permission_delegate_->HasAutoSigninPermission();
auto_signin_permission_delegate_->HasAutoSigninPermission(
GetEmbeddingOrigin());
if (maybe_proceed_with_auto_signin) {
const IdentityProviderData* auto_signin_idp = nullptr;
@ -936,6 +937,11 @@ void FederatedAuthRequestImpl::MaybeShowAccountsDialog() {
idp.accounts = {account};
idp_data_for_display = {idp};
}
// Embargo auto sign-in to mitigate a deadloop where an auto signed-in user
// gets re-auto signed-in soon after logging out of the active session.
auto_signin_permission_delegate_->RecordDisplayAndEmbargo(
GetEmbeddingOrigin());
}
// TODO(crbug.com/1408520): opt-out affordance is not included in the origin

@ -630,6 +630,16 @@ class TestPermissionDelegate : public NiceMock<MockPermissionDelegate> {
}
};
class TestAutoSigninPermissionDelegate
: public MockAutoSigninPermissionDelegate {
public:
std::set<url::Origin> embargoed_origins_;
void RecordDisplayAndEmbargo(const url::Origin& origin) override {
embargoed_origins_.insert(origin);
}
};
} // namespace
class FederatedAuthRequestImplTest : public RenderViewHostImplTestHarness {
@ -644,15 +654,15 @@ class FederatedAuthRequestImplTest : public RenderViewHostImplTestHarness {
test_api_permission_delegate_ =
std::make_unique<TestApiPermissionDelegate>();
test_permission_delegate_ = std::make_unique<TestPermissionDelegate>();
mock_auto_signin_permission_delegate_ =
std::make_unique<NiceMock<MockAutoSigninPermissionDelegate>>();
test_auto_signin_permission_delegate_ =
std::make_unique<TestAutoSigninPermissionDelegate>();
static_cast<TestWebContents*>(web_contents())
->NavigateAndCommit(GURL(kRpUrl), ui::PAGE_TRANSITION_LINK);
federated_auth_request_impl_ = &FederatedAuthRequestImpl::CreateForTesting(
*main_test_rfh(), test_api_permission_delegate_.get(),
mock_auto_signin_permission_delegate_.get(),
test_auto_signin_permission_delegate_.get(),
test_permission_delegate_.get(),
request_remote_.BindNewPipeAndPassReceiver());
@ -987,8 +997,8 @@ class FederatedAuthRequestImplTest : public RenderViewHostImplTestHarness {
std::unique_ptr<TestApiPermissionDelegate> test_api_permission_delegate_;
std::unique_ptr<TestPermissionDelegate> test_permission_delegate_;
std::unique_ptr<NiceMock<MockAutoSigninPermissionDelegate>>
mock_auto_signin_permission_delegate_;
std::unique_ptr<TestAutoSigninPermissionDelegate>
test_auto_signin_permission_delegate_;
AuthRequestCallbackHelper auth_helper_;
@ -1303,6 +1313,44 @@ TEST_F(FederatedAuthRequestImplTest,
EXPECT_TRUE(DidFetch(FetchedEndpoint::TOKEN));
}
// Test that auto sign-in permission is not embargoed upon explicit sign-in.
TEST_F(FederatedAuthRequestImplTest, ExplicitSigninEmbargo) {
RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
kConfigurationValid);
EXPECT_EQ(dialog_controller_state_.sign_in_mode, SignInMode::kExplicit);
EXPECT_TRUE(
test_auto_signin_permission_delegate_->embargoed_origins_.empty());
}
// Test that auto sign-in permission is embargoed upon successful auto sign-in.
TEST_F(FederatedAuthRequestImplTest, AutoSigninEmbargo) {
base::test::ScopedFeatureList list;
list.InitAndEnableFeature(features::kFedCmAutoReauthn);
// Pretend the sharing permission has been granted for this account.
EXPECT_CALL(
*test_permission_delegate_,
HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl),
OriginFromString(kProviderUrlFull), kAccountId))
.Times(2)
.WillRepeatedly(Return(true));
// Pretend the auto sign-in permission has been granted.
EXPECT_CALL(*test_auto_signin_permission_delegate_,
HasAutoSigninPermission(OriginFromString(kRpUrl)))
.WillOnce(Return(true));
RequestParameters request_parameters = kDefaultRequestParameters;
request_parameters.prefer_auto_sign_in = true;
RunAuthTest(request_parameters, kExpectationSuccess, kConfigurationValid);
ASSERT_EQ(displayed_accounts().size(), 1u);
EXPECT_EQ(displayed_accounts()[0].login_state, LoginState::kSignIn);
EXPECT_EQ(dialog_controller_state_.sign_in_mode, SignInMode::kAuto);
EXPECT_TRUE(test_auto_signin_permission_delegate_->embargoed_origins_.count(
OriginFromString(kRpUrl)));
}
// Test that auto sign-in with a single account where the account is a returning
// user sets the sign-in mode to auto.
TEST_F(FederatedAuthRequestImplTest,
@ -1319,7 +1367,8 @@ TEST_F(FederatedAuthRequestImplTest,
.WillRepeatedly(Return(true));
// Pretend the auto sign-in permission has been granted.
EXPECT_CALL(*mock_auto_signin_permission_delegate_, HasAutoSigninPermission())
EXPECT_CALL(*test_auto_signin_permission_delegate_,
HasAutoSigninPermission(OriginFromString(kRpUrl)))
.WillOnce(Return(true));
for (const auto& idp_info : kConfigurationValid.idp_info) {
@ -1364,7 +1413,8 @@ TEST_F(FederatedAuthRequestImplTest,
.WillOnce(Return(false));
// Pretend the auto sign-in permission has been granted.
EXPECT_CALL(*mock_auto_signin_permission_delegate_, HasAutoSigninPermission())
EXPECT_CALL(*test_auto_signin_permission_delegate_,
HasAutoSigninPermission(OriginFromString(kRpUrl)))
.WillOnce(Return(true));
RequestParameters request_parameters = kDefaultRequestParameters;
@ -1411,7 +1461,8 @@ TEST_F(FederatedAuthRequestImplTest,
.WillOnce(Return(false));
// Pretend the auto sign-in permission has been granted.
EXPECT_CALL(*mock_auto_signin_permission_delegate_, HasAutoSigninPermission())
EXPECT_CALL(*test_auto_signin_permission_delegate_,
HasAutoSigninPermission(OriginFromString(kRpUrl)))
.WillOnce(Return(true));
RequestParameters request_parameters = kDefaultRequestParameters;
@ -1442,7 +1493,8 @@ TEST_F(FederatedAuthRequestImplTest, AutoSigninForZeroReturningUsers) {
.WillOnce(Return(false));
// Pretend the auto sign-in permission has been granted.
EXPECT_CALL(*mock_auto_signin_permission_delegate_, HasAutoSigninPermission())
EXPECT_CALL(*test_auto_signin_permission_delegate_,
HasAutoSigninPermission(OriginFromString(kRpUrl)))
.WillOnce(Return(true));
for (const auto& idp_info : kConfigurationValid.idp_info) {
@ -1495,7 +1547,8 @@ TEST_F(FederatedAuthRequestImplTest, AutoSigninBrowserNotObservedSigninBefore) {
.WillRepeatedly(Return(false));
// Pretend the auto sign-in permission has been granted.
EXPECT_CALL(*mock_auto_signin_permission_delegate_, HasAutoSigninPermission())
EXPECT_CALL(*test_auto_signin_permission_delegate_,
HasAutoSigninPermission(OriginFromString(kRpUrl)))
.WillOnce(Return(true));
RequestParameters request_parameters = kDefaultRequestParameters;
@ -1520,7 +1573,8 @@ TEST_F(FederatedAuthRequestImplTest, AutoSigninForFirstTimeUser) {
list.InitAndEnableFeature(features::kFedCmAutoReauthn);
// Pretend the auto sign-in permission has been granted.
EXPECT_CALL(*mock_auto_signin_permission_delegate_, HasAutoSigninPermission())
EXPECT_CALL(*test_auto_signin_permission_delegate_,
HasAutoSigninPermission(OriginFromString(kRpUrl)))
.WillOnce(Return(true));
RequestParameters request_parameters = kDefaultRequestParameters;
@ -1547,7 +1601,8 @@ TEST_F(FederatedAuthRequestImplTest,
.WillOnce(Return(true));
// Pretend the auto sign-in permission has been blocked for this account.
EXPECT_CALL(*mock_auto_signin_permission_delegate_, HasAutoSigninPermission())
EXPECT_CALL(*test_auto_signin_permission_delegate_,
HasAutoSigninPermission(OriginFromString(kRpUrl)))
.WillOnce(Return(false));
RequestParameters request_parameters = kDefaultRequestParameters;

@ -22,7 +22,8 @@ class MockAutoSigninPermissionDelegate
MockAutoSigninPermissionDelegate& operator=(
const MockAutoSigninPermissionDelegate&) = delete;
MOCK_METHOD0(HasAutoSigninPermission, bool());
MOCK_METHOD1(HasAutoSigninPermission, bool(const url::Origin&));
MOCK_METHOD1(RecordDisplayAndEmbargo, void(const url::Origin&));
};
} // namespace content

@ -7,6 +7,10 @@
#include "content/common/content_export.h"
namespace url {
class Origin;
}
namespace content {
// Delegate interface for the FedCM implementation to query whether the FedCM
@ -16,8 +20,15 @@ class CONTENT_EXPORT FederatedIdentityAutoSigninPermissionContextDelegate {
FederatedIdentityAutoSigninPermissionContextDelegate() = default;
virtual ~FederatedIdentityAutoSigninPermissionContextDelegate() = default;
// Returns the permission status of the FedCM API's auto sign-in feature.
virtual bool HasAutoSigninPermission() = 0;
// Returns the permission status of the FedCM API's auto sign-in feature for
// the passed-in |relying_party_embedder|.
virtual bool HasAutoSigninPermission(
const url::Origin& relying_party_embedder) = 0;
// Records that an auto sign-in prompt was displayed to the user and places
// the permission under embargo for the passed-in |relying_party_embedder|.
virtual void RecordDisplayAndEmbargo(
const url::Origin& relying_party_embedder) = 0;
};
} // namespace content

@ -34,10 +34,14 @@ bool ShellFederatedPermissionContext::ShouldCompleteRequestImmediately() const {
}
// FederatedIdentityAutoSigninPermissionContextDelegate
bool ShellFederatedPermissionContext::HasAutoSigninPermission() {
bool ShellFederatedPermissionContext::HasAutoSigninPermission(
const url::Origin& relying_party_embedder) {
return auto_signin_permission_;
}
void ShellFederatedPermissionContext::RecordDisplayAndEmbargo(
const url::Origin& relying_party_embedder) {}
void ShellFederatedPermissionContext::AddIdpSigninStatusObserver(
IdpSigninStatusObserver* observer) {}
void ShellFederatedPermissionContext::RemoveIdpSigninStatusObserver(

@ -40,7 +40,10 @@ class ShellFederatedPermissionContext
bool ShouldCompleteRequestImmediately() const override;
// FederatedIdentityAutoSigninPermissionContextDelegate
bool HasAutoSigninPermission() override;
bool HasAutoSigninPermission(
const url::Origin& relying_party_embedder) override;
void RecordDisplayAndEmbargo(
const url::Origin& relying_party_embedder) override;
// FederatedIdentityPermissionContextDelegate
void AddIdpSigninStatusObserver(IdpSigninStatusObserver* observer) override;

@ -80715,6 +80715,7 @@ chromeos/ash/components/peripheral_notification/peripheral_notification_manager.
<int value="1" label="BLACKLISTED"/>
<int value="2" label="REPEATED_DISMISSALS"/>
<int value="3" label="REPEATED_IGNORES"/>
<int value="4" label="RECENT_DISPLAY"/>
</enum>
<enum name="PermissionPredictionSource">