1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/permissions/permission_context_base.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/test/mock_entropy_provider.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/permissions/permission_queue_controller.h"
#include "chrome/browser/permissions/permission_request_id.h"
#include "chrome/browser/permissions/permission_util.h"
#include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
#include "chrome/browser/permissions/permission_queue_controller.h"
#else
#include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
#endif
const char* kPermissionsKillSwitchFieldStudy =
PermissionContextBase::kPermissionsKillSwitchFieldStudy;
const char* kPermissionsKillSwitchBlockedValue =
PermissionContextBase::kPermissionsKillSwitchBlockedValue;
const char kPermissionsKillSwitchTestGroup[] = "TestGroup";
class TestPermissionContext : public PermissionContextBase {
public:
TestPermissionContext(Profile* profile,
const content::PermissionType permission_type,
const ContentSettingsType content_settings_type)
: PermissionContextBase(profile, permission_type, content_settings_type),
permission_set_(false),
permission_granted_(false),
tab_context_updated_(false),
field_trial_list_(
new base::FieldTrialList(new base::MockEntropyProvider)) {}
~TestPermissionContext() override {}
#if defined(OS_ANDROID)
PermissionQueueController* GetInfoBarController() {
return GetQueueController();
}
#endif
bool permission_granted() {
return permission_granted_;
}
bool permission_set() {
return permission_set_;
}
bool tab_context_updated() {
return tab_context_updated_;
}
void TrackPermissionDecision(ContentSetting content_setting) {
permission_set_ = true;
permission_granted_ = content_setting == CONTENT_SETTING_ALLOW;
}
void ResetFieldTrialList() {
// Destroy the existing FieldTrialList before creating a new one to avoid
// a DCHECK.
field_trial_list_.reset();
field_trial_list_.reset(new base::FieldTrialList(
new base::MockEntropyProvider));
variations::testing::ClearAllVariationParams();
}
protected:
void UpdateTabContext(const PermissionRequestID& id,
const GURL& requesting_origin,
bool allowed) override {
tab_context_updated_ = true;
}
bool IsRestrictedToSecureOrigins() const override {
return false;
}
private:
bool permission_set_;
bool permission_granted_;
bool tab_context_updated_;
scoped_ptr<base::FieldTrialList> field_trial_list_;
};
class PermissionContextBaseTests : public ChromeRenderViewHostTestHarness {
protected:
PermissionContextBaseTests() {}
// Accept or dismiss the permission bubble or infobar.
void RespondToPermission(TestPermissionContext* context,
const PermissionRequestID& id,
const GURL& url,
bool accept) {
#if defined(OS_ANDROID)
context->GetInfoBarController()->OnPermissionSet(id, url, url, accept,
accept);
#else
PermissionBubbleManager* manager =
PermissionBubbleManager::FromWebContents(web_contents());
if (accept)
manager->Accept();
else
manager->Closing();
#endif
}
void TestAskAndGrant_TestContent() {
TestPermissionContext permission_context(
profile(), content::PermissionType::NOTIFICATIONS,
CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
GURL url("http://www.google.com");
content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
const PermissionRequestID id(
web_contents()->GetRenderProcessHost()->GetID(),
web_contents()->GetMainFrame()->GetRoutingID(),
-1);
permission_context.RequestPermission(
web_contents(),
id, url, true,
base::Bind(&TestPermissionContext::TrackPermissionDecision,
base::Unretained(&permission_context)));
RespondToPermission(&permission_context, id, url, true);
EXPECT_TRUE(permission_context.permission_set());
EXPECT_TRUE(permission_context.permission_granted());
EXPECT_TRUE(permission_context.tab_context_updated());
ContentSetting setting =
HostContentSettingsMapFactory::GetForProfile(profile())
->GetContentSetting(url.GetOrigin(),
url.GetOrigin(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string());
EXPECT_EQ(CONTENT_SETTING_ALLOW, setting);
}
void TestAskAndDismiss_TestContent() {
TestPermissionContext permission_context(
profile(), content::PermissionType::MIDI_SYSEX,
CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
GURL url("http://www.google.es");
content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
const PermissionRequestID id(
web_contents()->GetRenderProcessHost()->GetID(),
web_contents()->GetMainFrame()->GetRoutingID(),
-1);
permission_context.RequestPermission(
web_contents(),
id, url, true,
base::Bind(&TestPermissionContext::TrackPermissionDecision,
base::Unretained(&permission_context)));
RespondToPermission(&permission_context, id, url, false);
EXPECT_TRUE(permission_context.permission_set());
EXPECT_FALSE(permission_context.permission_granted());
EXPECT_TRUE(permission_context.tab_context_updated());
ContentSetting setting =
HostContentSettingsMapFactory::GetForProfile(profile())
->GetContentSetting(url.GetOrigin(),
url.GetOrigin(),
CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
std::string());
EXPECT_EQ(CONTENT_SETTING_ASK, setting);
}
void TestRequestPermissionInvalidUrl(
content::PermissionType permission_type,
ContentSettingsType content_settings_type) {
TestPermissionContext permission_context(profile(), permission_type,
content_settings_type);
GURL url;
ASSERT_FALSE(url.is_valid());
content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
const PermissionRequestID id(
web_contents()->GetRenderProcessHost()->GetID(),
web_contents()->GetMainFrame()->GetRoutingID(),
-1);
permission_context.RequestPermission(
web_contents(),
id, url, true,
base::Bind(&TestPermissionContext::TrackPermissionDecision,
base::Unretained(&permission_context)));
EXPECT_TRUE(permission_context.permission_set());
EXPECT_FALSE(permission_context.permission_granted());
EXPECT_TRUE(permission_context.tab_context_updated());
ContentSetting setting =
HostContentSettingsMapFactory::GetForProfile(profile())
->GetContentSetting(url.GetOrigin(), url.GetOrigin(),
content_settings_type, std::string());
EXPECT_EQ(CONTENT_SETTING_ASK, setting);
}
void TestGrantAndRevoke_TestContent(content::PermissionType permission_type,
ContentSettingsType content_settings_type,
ContentSetting expected_default) {
TestPermissionContext permission_context(profile(), permission_type,
content_settings_type);
GURL url("https://www.google.com");
content::WebContentsTester::For(web_contents())->NavigateAndCommit(url);
const PermissionRequestID id(
web_contents()->GetRenderProcessHost()->GetID(),
web_contents()->GetMainFrame()->GetRoutingID(),
-1);
permission_context.RequestPermission(
web_contents(),
id, url, true,
base::Bind(&TestPermissionContext::TrackPermissionDecision,
base::Unretained(&permission_context)));
RespondToPermission(&permission_context, id, url, true);
EXPECT_TRUE(permission_context.permission_set());
EXPECT_TRUE(permission_context.permission_granted());
EXPECT_TRUE(permission_context.tab_context_updated());
ContentSetting setting =
HostContentSettingsMapFactory::GetForProfile(profile())
->GetContentSetting(url.GetOrigin(), url.GetOrigin(),
content_settings_type, std::string());
EXPECT_EQ(CONTENT_SETTING_ALLOW, setting);
// Try to reset permission.
permission_context.ResetPermission(url.GetOrigin(), url.GetOrigin());
ContentSetting setting_after_reset =
HostContentSettingsMapFactory::GetForProfile(profile())
->GetContentSetting(url.GetOrigin(), url.GetOrigin(),
content_settings_type, std::string());
ContentSetting default_setting =
HostContentSettingsMapFactory::GetForProfile(profile())
->GetDefaultContentSetting(content_settings_type, nullptr);
EXPECT_EQ(default_setting, setting_after_reset);
}
void TestGlobalPermissionsKillSwitch(
content::PermissionType permission_type,
ContentSettingsType content_settings_type) {
TestPermissionContext permission_context(profile(), permission_type,
content_settings_type);
permission_context.ResetFieldTrialList();
EXPECT_FALSE(permission_context.IsPermissionKillSwitchOn());
std::map<std::string, std::string> params;
params[PermissionUtil::GetPermissionString(permission_type)] =
kPermissionsKillSwitchBlockedValue;
variations::AssociateVariationParams(
kPermissionsKillSwitchFieldStudy, kPermissionsKillSwitchTestGroup,
params);
base::FieldTrialList::CreateFieldTrial(kPermissionsKillSwitchFieldStudy,
kPermissionsKillSwitchTestGroup);
EXPECT_TRUE(permission_context.IsPermissionKillSwitchOn());
}
private:
// ChromeRenderViewHostTestHarness:
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
#if defined(OS_ANDROID)
InfoBarService::CreateForWebContents(web_contents());
#else
PermissionBubbleManager::CreateForWebContents(web_contents());
#endif
}
DISALLOW_COPY_AND_ASSIGN(PermissionContextBaseTests);
};
// Simulates clicking Accept. The permission should be granted and
// saved for future use.
TEST_F(PermissionContextBaseTests, TestAskAndGrant) {
TestAskAndGrant_TestContent();
}
// Simulates clicking Dismiss (X) in the infobar/bubble.
// The permission should be denied but not saved for future use.
TEST_F(PermissionContextBaseTests, TestAskAndDismiss) {
TestAskAndDismiss_TestContent();
}
// Simulates non-valid requesting URL.
// The permission should be denied but not saved for future use.
TEST_F(PermissionContextBaseTests, TestNonValidRequestingUrl) {
TestRequestPermissionInvalidUrl(content::PermissionType::GEOLOCATION,
CONTENT_SETTINGS_TYPE_GEOLOCATION);
TestRequestPermissionInvalidUrl(content::PermissionType::NOTIFICATIONS,
CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
TestRequestPermissionInvalidUrl(content::PermissionType::MIDI_SYSEX,
CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
TestRequestPermissionInvalidUrl(content::PermissionType::PUSH_MESSAGING,
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
TestRequestPermissionInvalidUrl(
content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
#endif
}
#if defined(OS_ANDROID)
// This test is specific to Android because other platforms use bubbles.
TEST_F(PermissionContextBaseTests, TestGrantAndRevokeWithInfobars) {
TestGrantAndRevoke_TestContent(content::PermissionType::GEOLOCATION,
CONTENT_SETTINGS_TYPE_GEOLOCATION,
CONTENT_SETTING_ASK);
TestGrantAndRevoke_TestContent(content::PermissionType::MIDI_SYSEX,
CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
CONTENT_SETTING_ASK);
TestGrantAndRevoke_TestContent(
content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, CONTENT_SETTING_ASK);
// TODO(timvolodine): currently no test for
// CONTENT_SETTINGS_TYPE_NOTIFICATIONS because notification permissions work
// differently with infobars as compared to bubbles (crbug.com/453784).
// TODO(timvolodine): currently no test for
// CONTENT_SETTINGS_TYPE_PUSH_MESSAGING because infobars do not implement push
// messaging permissions (crbug.com/453788).
}
#endif
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Simulates granting and revoking of permissions using permission bubbles.
// This test shouldn't run on mobile because mobile platforms use infobars.
TEST_F(PermissionContextBaseTests, TestGrantAndRevokeWithBubbles) {
TestGrantAndRevoke_TestContent(content::PermissionType::GEOLOCATION,
CONTENT_SETTINGS_TYPE_GEOLOCATION,
CONTENT_SETTING_ASK);
#if defined(ENABLE_NOTIFICATIONS)
TestGrantAndRevoke_TestContent(content::PermissionType::NOTIFICATIONS,
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
CONTENT_SETTING_ASK);
#endif
TestGrantAndRevoke_TestContent(content::PermissionType::MIDI_SYSEX,
CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
CONTENT_SETTING_ASK);
TestGrantAndRevoke_TestContent(content::PermissionType::PUSH_MESSAGING,
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
CONTENT_SETTING_ASK);
}
#endif
// Tests the global kill switch by enabling/disabling the Field Trials.
TEST_F(PermissionContextBaseTests, TestGlobalKillSwitch) {
TestGlobalPermissionsKillSwitch(content::PermissionType::GEOLOCATION,
CONTENT_SETTINGS_TYPE_GEOLOCATION);
TestGlobalPermissionsKillSwitch(content::PermissionType::NOTIFICATIONS,
CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
TestGlobalPermissionsKillSwitch(content::PermissionType::MIDI_SYSEX,
CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
TestGlobalPermissionsKillSwitch(content::PermissionType::PUSH_MESSAGING,
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
TestGlobalPermissionsKillSwitch(content::PermissionType::DURABLE_STORAGE,
CONTENT_SETTINGS_TYPE_DURABLE_STORAGE);
#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
TestGlobalPermissionsKillSwitch(
content::PermissionType::PROTECTED_MEDIA_IDENTIFIER,
CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
#endif
TestGlobalPermissionsKillSwitch(content::PermissionType::AUDIO_CAPTURE,
CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
TestGlobalPermissionsKillSwitch(content::PermissionType::VIDEO_CAPTURE,
CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
}
|