[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:

committed by
Chromium LUCI CQ

parent
2119018fbb
commit
11b28b1c63
chrome/browser/webid
federated_identity_auto_signin_permission_context.ccfederated_identity_auto_signin_permission_context.hfederated_identity_auto_signin_permission_context_unittest.cc
components/permissions
features.ccfeatures.hpermission_context_base.ccpermission_decision_auto_blocker.ccpermission_decision_auto_blocker.hpermission_decision_auto_blocker_unittest.ccpermission_result.hpermission_uma_util.ccpermission_uma_util.h
content
browser
webid
public
shell
tools/metrics/histograms
@ -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">
|
||||
|
Reference in New Issue
Block a user