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