1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/permissions/permission_context_base.h"
6
7 #include <map>
8 #include <set>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/feature_list.h"
15 #include "base/macros.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/metrics/field_trial_params.h"
18 #include "base/run_loop.h"
19 #include "base/test/metrics/histogram_tester.h"
20 #include "base/test/scoped_feature_list.h"
21 #include "build/build_config.h"
22 #include "components/content_settings/core/browser/host_content_settings_map.h"
23 #include "components/content_settings/core/common/content_settings.h"
24 #include "components/content_settings/core/common/content_settings_types.h"
25 #include "components/permissions/features.h"
26 #include "components/permissions/permission_decision_auto_blocker.h"
27 #include "components/permissions/permission_request_id.h"
28 #include "components/permissions/permission_request_manager.h"
29 #include "components/permissions/permission_uma_util.h"
30 #include "components/permissions/permission_util.h"
31 #include "components/permissions/test/mock_permission_prompt_factory.h"
32 #include "components/permissions/test/test_permissions_client.h"
33 #include "components/ukm/content/source_url_recorder.h"
34 #include "components/ukm/test_ukm_recorder.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/navigation_entry.h"
37 #include "content/public/browser/render_frame_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/test/mock_render_process_host.h"
40 #include "content/public/test/test_renderer_host.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "url/url_util.h"
43
44 namespace permissions {
45
46 const char* const kPermissionsKillSwitchFieldStudy =
47 PermissionContextBase::kPermissionsKillSwitchFieldStudy;
48 const char* const kPermissionsKillSwitchBlockedValue =
49 PermissionContextBase::kPermissionsKillSwitchBlockedValue;
50 const char kPermissionsKillSwitchTestGroup[] = "TestGroup";
51
52 class TestPermissionContext : public PermissionContextBase {
53 public:
TestPermissionContext(content::BrowserContext * browser_context,const ContentSettingsType content_settings_type)54 TestPermissionContext(content::BrowserContext* browser_context,
55 const ContentSettingsType content_settings_type)
56 : PermissionContextBase(browser_context,
57 content_settings_type,
58 blink::mojom::FeaturePolicyFeature::kNotFound),
59 tab_context_updated_(false) {}
60
~TestPermissionContext()61 ~TestPermissionContext() override {}
62
decisions() const63 const std::vector<ContentSetting>& decisions() const { return decisions_; }
64
tab_context_updated() const65 bool tab_context_updated() const { return tab_context_updated_; }
66
67 // Once a decision for the requested permission has been made, run the
68 // callback.
TrackPermissionDecision(ContentSetting content_setting)69 void TrackPermissionDecision(ContentSetting content_setting) {
70 decisions_.push_back(content_setting);
71 // Null check required here as the quit_closure_ can also be run and reset
72 // first from within DecidePermission.
73 if (quit_closure_) {
74 quit_closure_.Run();
75 quit_closure_.Reset();
76 }
77 }
78
GetContentSettingFromMap(const GURL & url_a,const GURL & url_b)79 ContentSetting GetContentSettingFromMap(const GURL& url_a,
80 const GURL& url_b) {
81 auto* map = PermissionsClient::Get()->GetSettingsMap(browser_context());
82 return map->GetContentSetting(url_a.GetOrigin(), url_b.GetOrigin(),
83 content_settings_type(), std::string());
84 }
85
RequestPermission(content::WebContents * web_contents,const PermissionRequestID & id,const GURL & requesting_frame,bool user_gesture,BrowserPermissionCallback callback)86 void RequestPermission(content::WebContents* web_contents,
87 const PermissionRequestID& id,
88 const GURL& requesting_frame,
89 bool user_gesture,
90 BrowserPermissionCallback callback) override {
91 base::RunLoop run_loop;
92 quit_closure_ = run_loop.QuitClosure();
93 PermissionContextBase::RequestPermission(web_contents, id, requesting_frame,
94 true /* user_gesture */,
95 std::move(callback));
96 run_loop.Run();
97 }
98
DecidePermission(content::WebContents * web_contents,const PermissionRequestID & id,const GURL & requesting_origin,const GURL & embedding_origin,bool user_gesture,BrowserPermissionCallback callback)99 void DecidePermission(content::WebContents* web_contents,
100 const PermissionRequestID& id,
101 const GURL& requesting_origin,
102 const GURL& embedding_origin,
103 bool user_gesture,
104 BrowserPermissionCallback callback) override {
105 PermissionContextBase::DecidePermission(web_contents, id, requesting_origin,
106 embedding_origin, user_gesture,
107 std::move(callback));
108 if (respond_permission_) {
109 respond_permission_.Run();
110 respond_permission_.Reset();
111 } else {
112 // Stop the run loop from spinning indefinitely if no response callback
113 // has been set, as is the case with TestParallelRequests.
114 quit_closure_.Run();
115 quit_closure_.Reset();
116 }
117 }
118
119 // Set the callback to run if the permission is being responded to in the
120 // test. This is left empty where no response is needed, such as in parallel
121 // requests, invalid origin, and killswitch.
SetRespondPermissionCallback(base::Closure callback)122 void SetRespondPermissionCallback(base::Closure callback) {
123 respond_permission_ = callback;
124 }
125
126 protected:
UpdateTabContext(const PermissionRequestID & id,const GURL & requesting_origin,bool allowed)127 void UpdateTabContext(const PermissionRequestID& id,
128 const GURL& requesting_origin,
129 bool allowed) override {
130 tab_context_updated_ = true;
131 }
132
IsRestrictedToSecureOrigins() const133 bool IsRestrictedToSecureOrigins() const override { return false; }
134
135 private:
136 std::vector<ContentSetting> decisions_;
137 bool tab_context_updated_;
138 base::Closure quit_closure_;
139 // Callback for responding to a permission once the request has been completed
140 // (valid URL, kill switch disabled)
141 base::Closure respond_permission_;
142 DISALLOW_COPY_AND_ASSIGN(TestPermissionContext);
143 };
144
145 class TestKillSwitchPermissionContext : public TestPermissionContext {
146 public:
TestKillSwitchPermissionContext(content::BrowserContext * browser_context,const ContentSettingsType content_settings_type)147 TestKillSwitchPermissionContext(
148 content::BrowserContext* browser_context,
149 const ContentSettingsType content_settings_type)
150 : TestPermissionContext(browser_context, content_settings_type) {
151 ResetFieldTrialList();
152 }
153
ResetFieldTrialList()154 void ResetFieldTrialList() {
155 scoped_feature_list_.Reset();
156 scoped_feature_list_.Init();
157 }
158
159 private:
160 base::test::ScopedFeatureList scoped_feature_list_;
161
162 DISALLOW_COPY_AND_ASSIGN(TestKillSwitchPermissionContext);
163 };
164
165 class TestSecureOriginRestrictedPermissionContext
166 : public TestPermissionContext {
167 public:
TestSecureOriginRestrictedPermissionContext(content::BrowserContext * browser_context,const ContentSettingsType content_settings_type)168 TestSecureOriginRestrictedPermissionContext(
169 content::BrowserContext* browser_context,
170 const ContentSettingsType content_settings_type)
171 : TestPermissionContext(browser_context, content_settings_type) {}
172
173 protected:
IsRestrictedToSecureOrigins() const174 bool IsRestrictedToSecureOrigins() const override { return true; }
175
176 private:
177 DISALLOW_COPY_AND_ASSIGN(TestSecureOriginRestrictedPermissionContext);
178 };
179
180 class TestPermissionsClientBypassExtensionOriginCheck
181 : public TestPermissionsClient {
182 public:
CanBypassEmbeddingOriginCheck(const GURL & requesting_origin,const GURL & embedding_origin)183 bool CanBypassEmbeddingOriginCheck(const GURL& requesting_origin,
184 const GURL& embedding_origin) override {
185 return requesting_origin.SchemeIs("chrome-extension");
186 }
187 };
188
189 class PermissionContextBaseTests : public content::RenderViewHostTestHarness {
190 protected:
PermissionContextBaseTests()191 PermissionContextBaseTests() {}
~PermissionContextBaseTests()192 ~PermissionContextBaseTests() override {}
193
194 // Accept or dismiss the permission prompt.
RespondToPermission(TestPermissionContext * context,const PermissionRequestID & id,const GURL & url,ContentSetting response)195 void RespondToPermission(TestPermissionContext* context,
196 const PermissionRequestID& id,
197 const GURL& url,
198 ContentSetting response) {
199 DCHECK(response == CONTENT_SETTING_ALLOW ||
200 response == CONTENT_SETTING_BLOCK ||
201 response == CONTENT_SETTING_ASK);
202 using AutoResponseType = PermissionRequestManager::AutoResponseType;
203 AutoResponseType decision = AutoResponseType::DISMISS;
204 if (response == CONTENT_SETTING_ALLOW)
205 decision = AutoResponseType::ACCEPT_ALL;
206 else if (response == CONTENT_SETTING_BLOCK)
207 decision = AutoResponseType::DENY_ALL;
208 prompt_factory_->set_response_type(decision);
209 }
210
TestAskAndDecide_TestContent(ContentSettingsType content_settings_type,ContentSetting decision)211 void TestAskAndDecide_TestContent(ContentSettingsType content_settings_type,
212 ContentSetting decision) {
213 ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
214 ukm::TestAutoSetUkmRecorder ukm_recorder;
215 TestPermissionContext permission_context(browser_context(),
216 content_settings_type);
217 GURL url("https://www.google.com");
218 SetUpUrl(url);
219 base::HistogramTester histograms;
220
221 const PermissionRequestID id(
222 web_contents()->GetMainFrame()->GetProcess()->GetID(),
223 web_contents()->GetMainFrame()->GetRoutingID(), -1);
224 permission_context.SetRespondPermissionCallback(base::Bind(
225 &PermissionContextBaseTests::RespondToPermission,
226 base::Unretained(this), &permission_context, id, url, decision));
227 permission_context.RequestPermission(
228 web_contents(), id, url, true /* user_gesture */,
229 base::Bind(&TestPermissionContext::TrackPermissionDecision,
230 base::Unretained(&permission_context)));
231 ASSERT_EQ(1u, permission_context.decisions().size());
232 EXPECT_EQ(decision, permission_context.decisions()[0]);
233 EXPECT_TRUE(permission_context.tab_context_updated());
234
235 std::string decision_string;
236 base::Optional<PermissionAction> action;
237 if (decision == CONTENT_SETTING_ALLOW) {
238 decision_string = "Accepted";
239 action = PermissionAction::GRANTED;
240 } else if (decision == CONTENT_SETTING_BLOCK) {
241 decision_string = "Denied";
242 action = PermissionAction::DENIED;
243 } else if (decision == CONTENT_SETTING_ASK) {
244 decision_string = "Dismissed";
245 action = PermissionAction::DISMISSED;
246 }
247
248 if (!decision_string.empty()) {
249 histograms.ExpectUniqueSample(
250 "Permissions.Prompt." + decision_string + ".PriorDismissCount." +
251 PermissionUtil::GetPermissionString(content_settings_type),
252 0, 1);
253 histograms.ExpectUniqueSample(
254 "Permissions.Prompt." + decision_string + ".PriorIgnoreCount." +
255 PermissionUtil::GetPermissionString(content_settings_type),
256 0, 1);
257 #if defined(OS_ANDROID)
258 histograms.ExpectUniqueSample(
259 "Permissions.Action.WithDisposition.ModalDialog",
260 static_cast<int>(action.value()), 1);
261 #else
262 histograms.ExpectUniqueSample(
263 "Permissions.Action.WithDisposition.AnchoredBubble",
264 static_cast<int>(action.value()), 1);
265 #endif
266 }
267
268 EXPECT_EQ(decision, permission_context.GetContentSettingFromMap(url, url));
269
270 histograms.ExpectUniqueSample(
271 "Permissions.AutoBlocker.EmbargoPromptSuppression",
272 static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), 1);
273 histograms.ExpectUniqueSample(
274 "Permissions.AutoBlocker.EmbargoStatus",
275 static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), 1);
276
277 if (action.has_value()) {
278 auto entries = ukm_recorder.GetEntriesByName("Permission");
279 EXPECT_EQ(1u, entries.size());
280 auto* entry = entries.front();
281 ukm_recorder.ExpectEntrySourceHasUrl(entry, url);
282
283 size_t num_values = 0;
284
285 EXPECT_NE(ContentSettingTypeToHistogramValue(content_settings_type,
286 &num_values),
287 -1);
288
289 EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "Source"),
290 static_cast<int64_t>(PermissionSourceUI::PROMPT));
291 EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "PermissionType"),
292 static_cast<int64_t>(ContentSettingTypeToHistogramValue(
293 content_settings_type, &num_values)));
294 EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "Action"),
295 static_cast<int64_t>(action.value()));
296
297 #if defined(OS_ANDROID)
298 EXPECT_EQ(
299 *ukm_recorder.GetEntryMetric(entry, "PromptDisposition"),
300 static_cast<int64_t>(PermissionPromptDisposition::MODAL_DIALOG));
301 #else
302 EXPECT_EQ(
303 *ukm_recorder.GetEntryMetric(entry, "PromptDisposition"),
304 static_cast<int64_t>(PermissionPromptDisposition::ANCHORED_BUBBLE));
305 #endif
306 }
307 }
308
DismissMultipleTimesAndExpectBlock(const GURL & url,ContentSettingsType content_settings_type,uint32_t iterations)309 void DismissMultipleTimesAndExpectBlock(
310 const GURL& url,
311 ContentSettingsType content_settings_type,
312 uint32_t iterations) {
313 base::HistogramTester histograms;
314
315 // Dismiss |iterations| times. The final dismiss should change the decision
316 // from dismiss to block, and hence change the persisted content setting.
317 for (uint32_t i = 0; i < iterations; ++i) {
318 TestPermissionContext permission_context(browser_context(),
319 content_settings_type);
320 const PermissionRequestID id(
321 web_contents()->GetMainFrame()->GetProcess()->GetID(),
322 web_contents()->GetMainFrame()->GetRoutingID(), i);
323
324 permission_context.SetRespondPermissionCallback(
325 base::Bind(&PermissionContextBaseTests::RespondToPermission,
326 base::Unretained(this), &permission_context, id, url,
327 CONTENT_SETTING_ASK));
328
329 permission_context.RequestPermission(
330 web_contents(), id, url, true /* user_gesture */,
331 base::Bind(&TestPermissionContext::TrackPermissionDecision,
332 base::Unretained(&permission_context)));
333 histograms.ExpectTotalCount(
334 "Permissions.Prompt.Dismissed.PriorDismissCount." +
335 PermissionUtil::GetPermissionString(content_settings_type),
336 i + 1);
337 histograms.ExpectBucketCount(
338 "Permissions.Prompt.Dismissed.PriorDismissCount." +
339 PermissionUtil::GetPermissionString(content_settings_type),
340 i, 1);
341
342 histograms.ExpectTotalCount("Permissions.AutoBlocker.EmbargoStatus",
343 i + 1);
344
345 PermissionResult result = permission_context.GetPermissionStatus(
346 nullptr /* render_frame_host */, url, url);
347
348 histograms.ExpectUniqueSample(
349 "Permissions.AutoBlocker.EmbargoPromptSuppression",
350 static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), i + 1);
351 if (i < 2) {
352 EXPECT_EQ(PermissionStatusSource::UNSPECIFIED, result.source);
353 EXPECT_EQ(CONTENT_SETTING_ASK, result.content_setting);
354 histograms.ExpectUniqueSample(
355 "Permissions.AutoBlocker.EmbargoStatus",
356 static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), i + 1);
357 } else {
358 EXPECT_EQ(PermissionStatusSource::MULTIPLE_DISMISSALS, result.source);
359 EXPECT_EQ(CONTENT_SETTING_BLOCK, result.content_setting);
360 histograms.ExpectBucketCount(
361 "Permissions.AutoBlocker.EmbargoStatus",
362 static_cast<int>(PermissionEmbargoStatus::REPEATED_DISMISSALS), 1);
363 }
364
365 ASSERT_EQ(1u, permission_context.decisions().size());
366 EXPECT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]);
367 EXPECT_TRUE(permission_context.tab_context_updated());
368 }
369
370 TestPermissionContext permission_context(browser_context(),
371 content_settings_type);
372 const PermissionRequestID id(
373 web_contents()->GetMainFrame()->GetProcess()->GetID(),
374 web_contents()->GetMainFrame()->GetRoutingID(), -1);
375
376 permission_context.SetRespondPermissionCallback(
377 base::Bind(&PermissionContextBaseTests::RespondToPermission,
378 base::Unretained(this), &permission_context, id, url,
379 CONTENT_SETTING_ASK));
380
381 permission_context.RequestPermission(
382 web_contents(), id, url, true /* user_gesture */,
383 base::Bind(&TestPermissionContext::TrackPermissionDecision,
384 base::Unretained(&permission_context)));
385
386 PermissionResult result = permission_context.GetPermissionStatus(
387 nullptr /* render_frame_host */, url, url);
388 EXPECT_EQ(CONTENT_SETTING_BLOCK, result.content_setting);
389 EXPECT_EQ(PermissionStatusSource::MULTIPLE_DISMISSALS, result.source);
390 histograms.ExpectBucketCount(
391 "Permissions.AutoBlocker.EmbargoPromptSuppression",
392 static_cast<int>(PermissionEmbargoStatus::REPEATED_DISMISSALS), 1);
393 }
394
TestBlockOnSeveralDismissals_TestContent()395 void TestBlockOnSeveralDismissals_TestContent() {
396 GURL url("https://www.google.com");
397 SetUpUrl(url);
398 base::HistogramTester histograms;
399
400 {
401 // Ensure that > 3 dismissals behaves correctly when the
402 // BlockPromptsIfDismissedOften feature is off.
403 base::test::ScopedFeatureList feature_list;
404 feature_list.InitAndDisableFeature(
405 features::kBlockPromptsIfDismissedOften);
406
407 for (uint32_t i = 0; i < 4; ++i) {
408 TestPermissionContext permission_context(
409 browser_context(), ContentSettingsType::GEOLOCATION);
410
411 const PermissionRequestID id(
412 web_contents()->GetMainFrame()->GetProcess()->GetID(),
413 web_contents()->GetMainFrame()->GetRoutingID(), i);
414
415 permission_context.SetRespondPermissionCallback(
416 base::Bind(&PermissionContextBaseTests::RespondToPermission,
417 base::Unretained(this), &permission_context, id, url,
418 CONTENT_SETTING_ASK));
419 permission_context.RequestPermission(
420 web_contents(), id, url, true /* user_gesture */,
421 base::Bind(&TestPermissionContext::TrackPermissionDecision,
422 base::Unretained(&permission_context)));
423 histograms.ExpectTotalCount(
424 "Permissions.Prompt.Dismissed.PriorDismissCount.Geolocation",
425 i + 1);
426 histograms.ExpectBucketCount(
427 "Permissions.Prompt.Dismissed.PriorDismissCount.Geolocation", i, 1);
428 histograms.ExpectUniqueSample(
429 "Permissions.AutoBlocker.EmbargoPromptSuppression",
430 static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), i + 1);
431 histograms.ExpectUniqueSample(
432 "Permissions.AutoBlocker.EmbargoStatus",
433 static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), i + 1);
434
435 ASSERT_EQ(1u, permission_context.decisions().size());
436 EXPECT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]);
437 EXPECT_TRUE(permission_context.tab_context_updated());
438 EXPECT_EQ(CONTENT_SETTING_ASK,
439 permission_context.GetContentSettingFromMap(url, url));
440 }
441
442 // Flush the dismissal counts.
443 auto* map = PermissionsClient::Get()->GetSettingsMap(browser_context());
444 map->ClearSettingsForOneType(
445 ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA);
446 }
447
448 EXPECT_TRUE(
449 base::FeatureList::IsEnabled(features::kBlockPromptsIfDismissedOften));
450
451 // Sanity check independence per permission type by checking two of them.
452 DismissMultipleTimesAndExpectBlock(url, ContentSettingsType::GEOLOCATION,
453 3);
454 DismissMultipleTimesAndExpectBlock(url, ContentSettingsType::NOTIFICATIONS,
455 3);
456 }
457
TestVariationBlockOnSeveralDismissals_TestContent()458 void TestVariationBlockOnSeveralDismissals_TestContent() {
459 GURL url("https://www.google.com");
460 SetUpUrl(url);
461 base::HistogramTester histograms;
462
463 std::map<std::string, std::string> params;
464 params
465 [PermissionDecisionAutoBlocker::GetPromptDismissCountKeyForTesting()] =
466 "5";
467 base::test::ScopedFeatureList scoped_feature_list;
468 scoped_feature_list.InitAndEnableFeatureWithParameters(
469 features::kBlockPromptsIfDismissedOften, params);
470
471 std::map<std::string, std::string> actual_params;
472 EXPECT_TRUE(base::GetFieldTrialParamsByFeature(
473 features::kBlockPromptsIfDismissedOften, &actual_params));
474 EXPECT_EQ(params, actual_params);
475
476 {
477 std::map<std::string, std::string> actual_params;
478 EXPECT_TRUE(base::GetFieldTrialParamsByFeature(
479 features::kBlockPromptsIfDismissedOften, &actual_params));
480 EXPECT_EQ(params, actual_params);
481 }
482
483 for (uint32_t i = 0; i < 5; ++i) {
484 TestPermissionContext permission_context(browser_context(),
485 ContentSettingsType::MIDI_SYSEX);
486
487 const PermissionRequestID id(
488 web_contents()->GetMainFrame()->GetProcess()->GetID(),
489 web_contents()->GetMainFrame()->GetRoutingID(), i);
490 permission_context.SetRespondPermissionCallback(
491 base::Bind(&PermissionContextBaseTests::RespondToPermission,
492 base::Unretained(this), &permission_context, id, url,
493 CONTENT_SETTING_ASK));
494 permission_context.RequestPermission(
495 web_contents(), id, url, true /* user_gesture */,
496 base::Bind(&TestPermissionContext::TrackPermissionDecision,
497 base::Unretained(&permission_context)));
498
499 EXPECT_EQ(1u, permission_context.decisions().size());
500 ASSERT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]);
501 EXPECT_TRUE(permission_context.tab_context_updated());
502 PermissionResult result = permission_context.GetPermissionStatus(
503 nullptr /* render_frame_host */, url, url);
504
505 histograms.ExpectTotalCount(
506 "Permissions.Prompt.Dismissed.PriorDismissCount.MidiSysEx", i + 1);
507 histograms.ExpectBucketCount(
508 "Permissions.Prompt.Dismissed.PriorDismissCount.MidiSysEx", i, 1);
509 histograms.ExpectUniqueSample(
510 "Permissions.AutoBlocker.EmbargoPromptSuppression",
511 static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), i + 1);
512 histograms.ExpectTotalCount("Permissions.AutoBlocker.EmbargoStatus",
513 i + 1);
514 if (i < 4) {
515 EXPECT_EQ(CONTENT_SETTING_ASK, result.content_setting);
516 EXPECT_EQ(PermissionStatusSource::UNSPECIFIED, result.source);
517 histograms.ExpectUniqueSample(
518 "Permissions.AutoBlocker.EmbargoStatus",
519 static_cast<int>(PermissionEmbargoStatus::NOT_EMBARGOED), i + 1);
520 } else {
521 EXPECT_EQ(CONTENT_SETTING_BLOCK, result.content_setting);
522 EXPECT_EQ(PermissionStatusSource::MULTIPLE_DISMISSALS, result.source);
523 histograms.ExpectBucketCount(
524 "Permissions.AutoBlocker.EmbargoStatus",
525 static_cast<int>(PermissionEmbargoStatus::REPEATED_DISMISSALS), 1);
526 }
527 }
528
529 // Ensure that we finish in the block state.
530 TestPermissionContext permission_context(browser_context(),
531 ContentSettingsType::MIDI_SYSEX);
532 PermissionResult result = permission_context.GetPermissionStatus(
533 nullptr /* render_frame_host */, url, url);
534 EXPECT_EQ(CONTENT_SETTING_BLOCK, result.content_setting);
535 EXPECT_EQ(PermissionStatusSource::MULTIPLE_DISMISSALS, result.source);
536 }
537
TestRequestPermissionInvalidUrl(ContentSettingsType content_settings_type)538 void TestRequestPermissionInvalidUrl(
539 ContentSettingsType content_settings_type) {
540 base::HistogramTester histograms;
541 TestPermissionContext permission_context(browser_context(),
542 content_settings_type);
543 GURL url;
544 ASSERT_FALSE(url.is_valid());
545 controller().LoadURL(url, content::Referrer(), ui::PAGE_TRANSITION_TYPED,
546 std::string());
547
548 const PermissionRequestID id(
549 web_contents()->GetMainFrame()->GetProcess()->GetID(),
550 web_contents()->GetMainFrame()->GetRoutingID(), -1);
551 permission_context.RequestPermission(
552 web_contents(), id, url, true /* user_gesture */,
553 base::Bind(&TestPermissionContext::TrackPermissionDecision,
554 base::Unretained(&permission_context)));
555
556 ASSERT_EQ(1u, permission_context.decisions().size());
557 EXPECT_EQ(CONTENT_SETTING_BLOCK, permission_context.decisions()[0]);
558 EXPECT_TRUE(permission_context.tab_context_updated());
559 EXPECT_EQ(CONTENT_SETTING_ASK,
560 permission_context.GetContentSettingFromMap(url, url));
561 histograms.ExpectTotalCount(
562 "Permissions.AutoBlocker.EmbargoPromptSuppression", 0);
563 }
564
TestGrantAndRevoke_TestContent(ContentSettingsType content_settings_type,ContentSetting expected_default)565 void TestGrantAndRevoke_TestContent(ContentSettingsType content_settings_type,
566 ContentSetting expected_default) {
567 TestPermissionContext permission_context(browser_context(),
568 content_settings_type);
569 GURL url("https://www.google.com");
570 SetUpUrl(url);
571
572 const PermissionRequestID id(
573 web_contents()->GetMainFrame()->GetProcess()->GetID(),
574 web_contents()->GetMainFrame()->GetRoutingID(), -1);
575 permission_context.SetRespondPermissionCallback(
576 base::Bind(&PermissionContextBaseTests::RespondToPermission,
577 base::Unretained(this), &permission_context, id, url,
578 CONTENT_SETTING_ALLOW));
579
580 permission_context.RequestPermission(
581 web_contents(), id, url, true /* user_gesture */,
582 base::Bind(&TestPermissionContext::TrackPermissionDecision,
583 base::Unretained(&permission_context)));
584
585 ASSERT_EQ(1u, permission_context.decisions().size());
586 EXPECT_EQ(CONTENT_SETTING_ALLOW, permission_context.decisions()[0]);
587 EXPECT_TRUE(permission_context.tab_context_updated());
588 EXPECT_EQ(CONTENT_SETTING_ALLOW,
589 permission_context.GetContentSettingFromMap(url, url));
590
591 // Try to reset permission.
592 permission_context.ResetPermission(url.GetOrigin(), url.GetOrigin());
593 ContentSetting setting_after_reset =
594 permission_context.GetContentSettingFromMap(url, url);
595 ContentSetting default_setting =
596 PermissionsClient::Get()
597 ->GetSettingsMap(browser_context())
598 ->GetDefaultContentSetting(content_settings_type, nullptr);
599 EXPECT_EQ(default_setting, setting_after_reset);
600 }
601
TestGlobalPermissionsKillSwitch(ContentSettingsType content_settings_type)602 void TestGlobalPermissionsKillSwitch(
603 ContentSettingsType content_settings_type) {
604 TestKillSwitchPermissionContext permission_context(browser_context(),
605 content_settings_type);
606 permission_context.ResetFieldTrialList();
607
608 EXPECT_FALSE(permission_context.IsPermissionKillSwitchOn());
609 std::map<std::string, std::string> params;
610 params[PermissionUtil::GetPermissionString(content_settings_type)] =
611 kPermissionsKillSwitchBlockedValue;
612 base::AssociateFieldTrialParams(kPermissionsKillSwitchFieldStudy,
613 kPermissionsKillSwitchTestGroup, params);
614 base::FieldTrialList::CreateFieldTrial(kPermissionsKillSwitchFieldStudy,
615 kPermissionsKillSwitchTestGroup);
616 EXPECT_TRUE(permission_context.IsPermissionKillSwitchOn());
617 }
618
TestSecureOriginRestrictedPermissionContextCheck(const std::string & requesting_url_spec,const std::string & embedding_url_spec,bool expect_allowed)619 void TestSecureOriginRestrictedPermissionContextCheck(
620 const std::string& requesting_url_spec,
621 const std::string& embedding_url_spec,
622 bool expect_allowed) {
623 GURL requesting_origin(requesting_url_spec);
624 GURL embedding_origin(embedding_url_spec);
625 TestSecureOriginRestrictedPermissionContext permission_context(
626 browser_context(), ContentSettingsType::GEOLOCATION);
627 bool result = permission_context.IsPermissionAvailableToOrigins(
628 requesting_origin, embedding_origin);
629 EXPECT_EQ(expect_allowed, result)
630 << "test case (requesting, embedding): (" << requesting_url_spec << ", "
631 << embedding_url_spec << ") with secure-origin requirement"
632 << " on";
633
634 // With no secure-origin limitation, this check should always return pass.
635 TestPermissionContext new_context(browser_context(),
636 ContentSettingsType::GEOLOCATION);
637 result = new_context.IsPermissionAvailableToOrigins(requesting_origin,
638 embedding_origin);
639 EXPECT_EQ(true, result)
640 << "test case (requesting, embedding): (" << requesting_url_spec << ", "
641 << embedding_url_spec << ") with secure-origin requirement"
642 << " off";
643 }
644
645 // Don't call this more than once in the same test, as it persists data to
646 // HostContentSettingsMap.
TestParallelRequests(ContentSetting response)647 void TestParallelRequests(ContentSetting response) {
648 TestPermissionContext permission_context(browser_context(),
649 ContentSettingsType::GEOLOCATION);
650 GURL url("http://www.google.com");
651 SetUpUrl(url);
652
653 const PermissionRequestID id0(
654 web_contents()->GetMainFrame()->GetProcess()->GetID(),
655 web_contents()->GetMainFrame()->GetRoutingID(), 0);
656 const PermissionRequestID id1(
657 web_contents()->GetMainFrame()->GetProcess()->GetID(),
658 web_contents()->GetMainFrame()->GetRoutingID(), 1);
659
660 // Request a permission without setting the callback to DecidePermission.
661 permission_context.RequestPermission(
662 web_contents(), id0, url, true /* user_gesture */,
663 base::Bind(&TestPermissionContext::TrackPermissionDecision,
664 base::Unretained(&permission_context)));
665
666 EXPECT_EQ(0u, permission_context.decisions().size());
667
668 // Set the callback, and make a second permission request.
669 permission_context.SetRespondPermissionCallback(base::Bind(
670 &PermissionContextBaseTests::RespondToPermission,
671 base::Unretained(this), &permission_context, id0, url, response));
672 permission_context.RequestPermission(
673 web_contents(), id1, url, true /* user_gesture */,
674 base::Bind(&TestPermissionContext::TrackPermissionDecision,
675 base::Unretained(&permission_context)));
676
677 ASSERT_EQ(2u, permission_context.decisions().size());
678 EXPECT_EQ(response, permission_context.decisions()[0]);
679 EXPECT_EQ(response, permission_context.decisions()[1]);
680 EXPECT_TRUE(permission_context.tab_context_updated());
681
682 EXPECT_EQ(response, permission_context.GetContentSettingFromMap(url, url));
683 }
684
TestVirtualURL(const GURL & loaded_url,const GURL & virtual_url,const ContentSetting want_response,const PermissionStatusSource & want_source)685 void TestVirtualURL(const GURL& loaded_url,
686 const GURL& virtual_url,
687 const ContentSetting want_response,
688 const PermissionStatusSource& want_source) {
689 TestPermissionContext permission_context(browser_context(),
690 ContentSettingsType::GEOLOCATION);
691
692 NavigateAndCommit(loaded_url);
693 web_contents()->GetController().GetVisibleEntry()->SetVirtualURL(
694 virtual_url);
695
696 PermissionResult result = permission_context.GetPermissionStatus(
697 web_contents()->GetMainFrame(), virtual_url, virtual_url);
698 EXPECT_EQ(result.content_setting, want_response);
699 EXPECT_EQ(result.source, want_source);
700 }
701
SetUpUrl(const GURL & url)702 void SetUpUrl(const GURL& url) {
703 NavigateAndCommit(url);
704 prompt_factory_->DocumentOnLoadCompletedInMainFrame();
705 }
706
707 private:
708 // content::RenderViewHostTestHarness:
SetUp()709 void SetUp() override {
710 content::RenderViewHostTestHarness::SetUp();
711 PermissionRequestManager::CreateForWebContents(web_contents());
712 PermissionRequestManager* manager =
713 PermissionRequestManager::FromWebContents(web_contents());
714 prompt_factory_.reset(new MockPermissionPromptFactory(manager));
715 }
716
TearDown()717 void TearDown() override {
718 prompt_factory_.reset();
719 content::RenderViewHostTestHarness::TearDown();
720 }
721
722 std::unique_ptr<MockPermissionPromptFactory> prompt_factory_;
723 TestPermissionsClientBypassExtensionOriginCheck client_;
724
725 DISALLOW_COPY_AND_ASSIGN(PermissionContextBaseTests);
726 };
727
728 // Simulates clicking Accept. The permission should be granted and
729 // saved for future use.
TEST_F(PermissionContextBaseTests,TestAskAndGrant)730 TEST_F(PermissionContextBaseTests, TestAskAndGrant) {
731 TestAskAndDecide_TestContent(ContentSettingsType::NOTIFICATIONS,
732 CONTENT_SETTING_ALLOW);
733 }
734
735 // Simulates clicking Block. The permission should be denied and
736 // saved for future use.
TEST_F(PermissionContextBaseTests,TestAskAndBlock)737 TEST_F(PermissionContextBaseTests, TestAskAndBlock) {
738 TestAskAndDecide_TestContent(ContentSettingsType::GEOLOCATION,
739 CONTENT_SETTING_BLOCK);
740 }
741
742 // Simulates clicking Dismiss (X) in the prompt.
743 // The permission should be denied but not saved for future use.
TEST_F(PermissionContextBaseTests,TestAskAndDismiss)744 TEST_F(PermissionContextBaseTests, TestAskAndDismiss) {
745 TestAskAndDecide_TestContent(ContentSettingsType::MIDI_SYSEX,
746 CONTENT_SETTING_ASK);
747 }
748
749 // Simulates clicking Dismiss (X) in the prompt with the block on too
750 // many dismissals feature active. The permission should be blocked after
751 // several dismissals.
TEST_F(PermissionContextBaseTests,TestDismissUntilBlocked)752 TEST_F(PermissionContextBaseTests, TestDismissUntilBlocked) {
753 TestBlockOnSeveralDismissals_TestContent();
754 }
755
756 // Test setting a custom number of dismissals before block via variations.
TEST_F(PermissionContextBaseTests,TestDismissVariations)757 TEST_F(PermissionContextBaseTests, TestDismissVariations) {
758 TestVariationBlockOnSeveralDismissals_TestContent();
759 }
760
761 // Simulates non-valid requesting URL.
762 // The permission should be denied but not saved for future use.
TEST_F(PermissionContextBaseTests,TestNonValidRequestingUrl)763 TEST_F(PermissionContextBaseTests, TestNonValidRequestingUrl) {
764 TestRequestPermissionInvalidUrl(ContentSettingsType::GEOLOCATION);
765 TestRequestPermissionInvalidUrl(ContentSettingsType::NOTIFICATIONS);
766 TestRequestPermissionInvalidUrl(ContentSettingsType::MIDI_SYSEX);
767 #if defined(OS_CHROMEOS)
768 TestRequestPermissionInvalidUrl(
769 ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER);
770 #endif
771 }
772
773 // Simulates granting and revoking of permissions.
TEST_F(PermissionContextBaseTests,TestGrantAndRevoke)774 TEST_F(PermissionContextBaseTests, TestGrantAndRevoke) {
775 TestGrantAndRevoke_TestContent(ContentSettingsType::GEOLOCATION,
776 CONTENT_SETTING_ASK);
777 TestGrantAndRevoke_TestContent(ContentSettingsType::MIDI_SYSEX,
778 CONTENT_SETTING_ASK);
779 #if defined(OS_ANDROID)
780 TestGrantAndRevoke_TestContent(
781 ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER, CONTENT_SETTING_ASK);
782 // TODO(timvolodine): currently no test for
783 // ContentSettingsType::NOTIFICATIONS because notification permissions work
784 // differently with infobars as compared to bubbles (crbug.com/453784).
785 #else
786 TestGrantAndRevoke_TestContent(ContentSettingsType::NOTIFICATIONS,
787 CONTENT_SETTING_ASK);
788 #endif
789 }
790
791 // Tests the global kill switch by enabling/disabling the Field Trials.
TEST_F(PermissionContextBaseTests,TestGlobalKillSwitch)792 TEST_F(PermissionContextBaseTests, TestGlobalKillSwitch) {
793 TestGlobalPermissionsKillSwitch(ContentSettingsType::GEOLOCATION);
794 TestGlobalPermissionsKillSwitch(ContentSettingsType::NOTIFICATIONS);
795 TestGlobalPermissionsKillSwitch(ContentSettingsType::MIDI_SYSEX);
796 TestGlobalPermissionsKillSwitch(ContentSettingsType::DURABLE_STORAGE);
797 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
798 TestGlobalPermissionsKillSwitch(
799 ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER);
800 #endif
801 TestGlobalPermissionsKillSwitch(ContentSettingsType::MEDIASTREAM_MIC);
802 TestGlobalPermissionsKillSwitch(ContentSettingsType::MEDIASTREAM_CAMERA);
803 }
804
805 // Tests that secure origins are examined if switch is on, or ignored if off.
TEST_F(PermissionContextBaseTests,TestSecureOriginRestrictedPermissionContextSwitch)806 TEST_F(PermissionContextBaseTests,
807 TestSecureOriginRestrictedPermissionContextSwitch) {
808 url::ScopedSchemeRegistryForTests scoped_registry;
809 url::AddSecureScheme("chrome-extension");
810 struct {
811 std::string requesting_url_spec;
812 std::string embedding_url_spec;
813 bool expect_permission_allowed;
814 } kTestCases[] = {
815 // Secure-origins that should be allowed.
816 {"https://google.com", "https://foo.com",
817 /*expect_allowed=*/true},
818 {"https://www.bar.com", "https://foo.com",
819 /*expect_allowed=*/true},
820 {"https://localhost", "http://localhost",
821 /*expect_allowed=*/true},
822
823 {"http://localhost", "https://google.com",
824 /*expect_allowed=*/true},
825 {"https://google.com", "http://localhost",
826 /*expect_allowed=*/true},
827 {"https://foo.com", "file://some-file",
828 /*expect_allowed=*/true},
829 {"file://some-file", "https://foo.com",
830 /*expect_allowed=*/true},
831 {"https://foo.com", "about:blank",
832 /*expect_allowed=*/true},
833 {"about:blank", "https://foo.com",
834 /*expect_allowed=*/true},
835
836 // Extensions are exempt from checking the embedder chain.
837 {"chrome-extension://some-extension", "http://not-secure.com",
838 /*expect_allowed=*/true},
839
840 // Insecure-origins that should be blocked.
841 {"http://foo.com", "file://some-file",
842 /*expect_allowed=*/false},
843 {"fake://foo.com", "about:blank",
844 /*expect_allowed=*/false},
845 {"http://localhost", "http://foo.com",
846 /*expect_allowed=*/false},
847 {"http://localhost", "foo.com",
848 /*expect_allowed=*/false},
849 {"http://bar.com", "https://foo.com",
850 /*expect_permission_allowed=*/false},
851 {"https://foo.com", "http://bar.com",
852 /*expect_permission_allowed=*/false},
853 {"http://localhost", "http://foo.com",
854 /*expect_permission_allowed=*/false},
855 {"http://foo.com", "http://localhost",
856 /*expect_permission_allowed=*/false},
857 {"bar.com", "https://foo.com", /*expect_permission_allowed=*/false},
858 {"https://foo.com", "bar.com", /*expect_permission_allowed=*/false}};
859 for (const auto& test_case : kTestCases) {
860 TestSecureOriginRestrictedPermissionContextCheck(
861 test_case.requesting_url_spec, test_case.embedding_url_spec,
862 test_case.expect_permission_allowed);
863 }
864 }
865
TEST_F(PermissionContextBaseTests,TestParallelRequestsAllowed)866 TEST_F(PermissionContextBaseTests, TestParallelRequestsAllowed) {
867 TestParallelRequests(CONTENT_SETTING_ALLOW);
868 }
869
TEST_F(PermissionContextBaseTests,TestParallelRequestsBlocked)870 TEST_F(PermissionContextBaseTests, TestParallelRequestsBlocked) {
871 TestParallelRequests(CONTENT_SETTING_BLOCK);
872 }
873
TEST_F(PermissionContextBaseTests,TestParallelRequestsDismissed)874 TEST_F(PermissionContextBaseTests, TestParallelRequestsDismissed) {
875 TestParallelRequests(CONTENT_SETTING_ASK);
876 }
877
TEST_F(PermissionContextBaseTests,TestVirtualURLDifferentOrigin)878 TEST_F(PermissionContextBaseTests, TestVirtualURLDifferentOrigin) {
879 TestVirtualURL(GURL("http://www.google.com"), GURL("http://foo.com"),
880 CONTENT_SETTING_BLOCK,
881 PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN);
882 }
883
TEST_F(PermissionContextBaseTests,TestVirtualURLNotHTTP)884 TEST_F(PermissionContextBaseTests, TestVirtualURLNotHTTP) {
885 TestVirtualURL(GURL("chrome://foo"), GURL("chrome://newtab"),
886 CONTENT_SETTING_ASK, PermissionStatusSource::UNSPECIFIED);
887 }
888
TEST_F(PermissionContextBaseTests,TestVirtualURLSameOrigin)889 TEST_F(PermissionContextBaseTests, TestVirtualURLSameOrigin) {
890 TestVirtualURL(GURL("http://www.google.com"),
891 GURL("http://www.google.com/foo"), CONTENT_SETTING_ASK,
892 PermissionStatusSource::UNSPECIFIED);
893 }
894
895 } // namespace permissions
896