Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(257)

Side by Side Diff: chrome/browser/permissions/permission_context_base.cc

Issue 2555913002: Implement origin specific Permissions Blacklisting. (Closed)
Patch Set: Client inherits RefCountedThreadSafe. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/permissions/permission_context_base.h" 5 #include "chrome/browser/permissions/permission_context_base.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8
9 #include <set>
10 #include <string>
8 #include <utility> 11 #include <utility>
9 12
10 #include "base/callback.h" 13 #include "base/callback.h"
11 #include "base/logging.h" 14 #include "base/logging.h"
12 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
13 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
17 #include "base/timer/timer.h"
14 #include "build/build_config.h" 18 #include "build/build_config.h"
19 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" 20 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
16 #include "chrome/browser/permissions/permission_decision_auto_blocker.h" 21 #include "chrome/browser/permissions/permission_decision_auto_blocker.h"
17 #include "chrome/browser/permissions/permission_request.h" 22 #include "chrome/browser/permissions/permission_request.h"
18 #include "chrome/browser/permissions/permission_request_id.h" 23 #include "chrome/browser/permissions/permission_request_id.h"
19 #include "chrome/browser/permissions/permission_request_impl.h" 24 #include "chrome/browser/permissions/permission_request_impl.h"
20 #include "chrome/browser/permissions/permission_request_manager.h" 25 #include "chrome/browser/permissions/permission_request_manager.h"
21 #include "chrome/browser/permissions/permission_uma_util.h" 26 #include "chrome/browser/permissions/permission_uma_util.h"
22 #include "chrome/browser/permissions/permission_util.h" 27 #include "chrome/browser/permissions/permission_util.h"
23 #include "chrome/browser/profiles/profile.h" 28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
30 #include "chrome/common/chrome_features.h"
24 #include "chrome/common/pref_names.h" 31 #include "chrome/common/pref_names.h"
25 #include "components/content_settings/core/browser/host_content_settings_map.h" 32 #include "components/content_settings/core/browser/host_content_settings_map.h"
26 #include "components/content_settings/core/browser/website_settings_registry.h" 33 #include "components/content_settings/core/browser/website_settings_registry.h"
27 #include "components/prefs/pref_service.h" 34 #include "components/prefs/pref_service.h"
35 #include "components/safe_browsing_db/database_manager.h"
28 #include "components/variations/variations_associated_data.h" 36 #include "components/variations/variations_associated_data.h"
29 #include "content/public/browser/browser_thread.h" 37 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/render_frame_host.h" 38 #include "content/public/browser/render_frame_host.h"
31 #include "content/public/browser/web_contents.h" 39 #include "content/public/browser/web_contents.h"
40 #include "content/public/browser/web_contents_observer.h"
32 #include "content/public/common/origin_util.h" 41 #include "content/public/common/origin_util.h"
33 #include "url/gurl.h" 42 #include "url/gurl.h"
34 43
35 #if defined(OS_ANDROID) 44 #if defined(OS_ANDROID)
36 #include "chrome/browser/permissions/permission_queue_controller.h" 45 #include "chrome/browser/permissions/permission_queue_controller.h"
37 #endif 46 #endif
38 47
39 // static 48 // static
40 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] = 49 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] =
41 "PermissionsKillSwitch"; 50 "PermissionsKillSwitch";
42 // static 51 // static
43 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] = 52 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] =
44 "blocked"; 53 "blocked";
54 // Maximum time in milliseconds to wait for safe browsing service to check a
55 // url for blacklisting. After this amount of time, the check will be aborted
56 // and the url will be treated as not blacklisted.
57 const int kCheckUrlTimeoutMs = 1000;
kcarattini 2016/12/20 19:57:10 I'm concerned that this is too short. How about we
meredithl 2016/12/29 06:23:35 Done.
58
59 // The client used when checking whether a permission has been blacklisted by
60 // Safe Browsing. The check is done asynchronously as no state can be stored in
61 // PermissionContextBase (since additional permission requests may be made).
62 // This class must be created and destroyed on the UI thread.
63 class PermissionsBlacklistingClient
raymes 2016/12/20 23:58:57 This is a fairly substantial class now. I think it
meredithl 2016/12/29 06:23:35 Yep, that's in the works, which I'll be detailing
64 : public safe_browsing::SafeBrowsingDatabaseManager::Client,
65 public base::RefCountedThreadSafe<PermissionsBlacklistingClient>,
66 public content::WebContentsObserver {
67 public:
68 static void CheckSafeBrowsingBlacklist(
69 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager,
70 content::PermissionType permission_type,
71 const GURL& request_origin,
72 content::WebContents* web_contents,
73 int timeout,
raymes 2016/12/20 23:58:57 Could we just make this a member variable of the c
meredithl 2016/12/29 06:23:35 Done.
raymes 2017/01/09 06:28:17 Can we remove this as an argument from this functi
meredithl 2017/01/10 02:24:57 It gets passed from here into the constructor to b
raymes 2017/01/10 02:57:15 Oh sorry, you're right, we need it here :)
meredithl 2017/01/10 03:40:46 Acknowledged.
74 base::Callback<void(bool)> callback) {
75 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
76
77 new PermissionsBlacklistingClient(db_manager, permission_type,
78 request_origin, web_contents, timeout,
79 callback);
80 }
81
82 private:
83 friend class base::RefCountedThreadSafe<PermissionsBlacklistingClient>;
84 ~PermissionsBlacklistingClient() override {}
raymes 2016/12/20 23:58:57 nit: constructor before destructor usually
meredithl 2016/12/29 06:23:35 Done.
85
86 PermissionsBlacklistingClient(
87 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager,
88 content::PermissionType permission_type,
89 const GURL& request_origin,
90 content::WebContents* web_contents,
91 int timeout,
92 base::Callback<void(bool)> callback)
93 : content::WebContentsObserver(web_contents),
94 db_manager_(db_manager),
95 permission_type_(permission_type),
96 callback_(callback) {
97 // Balanced by a call to Release() in OnCheckApiBlacklistUrlResult().
98 AddRef();
99 content::BrowserThread::PostTask(
100 content::BrowserThread::IO, FROM_HERE,
101 base::Bind(&PermissionsBlacklistingClient::StartCheck, this,
102 request_origin, timeout));
103 }
104
105 void StartCheck(const GURL& request_origin, int timeout) {
raymes 2017/01/09 06:28:17 nit: Can we remove timeout here and just use timeo
meredithl 2017/01/10 02:24:57 Done.
106 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
107
108 // Start the timer to interrupt into the client callback method with an
109 // empty response if Safe Browsing times out.
110 safe_browsing::ThreatMetadata empty_metadata;
111 timer_ = base::MakeUnique<base::OneShotTimer>();
112 timer_->Start(
113 FROM_HERE, base::TimeDelta::FromMilliseconds(timeout),
114 base::Bind(&PermissionsBlacklistingClient::OnCheckApiBlacklistUrlResult,
115 this, request_origin, empty_metadata));
116 db_manager_->CheckApiBlacklistUrl(request_origin, this);
117 }
118
119 // SafeBrowsingDatabaseManager::Client implementation.
120 // TODO(meredithl) : fix this for post task
raymes 2016/12/20 23:58:57 I'm not sure what this comment means?
meredithl 2016/12/29 06:23:35 Sorry. Was an old comment for me to look at, forgo
121 void OnCheckApiBlacklistUrlResult(
122 const GURL& url,
123 const safe_browsing::ThreatMetadata& metadata) override {
124 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
125
126 if (timer_->IsRunning())
127 timer_->Stop();
128 else
129 db_manager_->CancelApiCheck(this);
130 timer_.reset(nullptr);
131
132 // TODO(meredithl) : Implement correct permission string check.
raymes 2016/12/20 23:58:57 Hmm I'm not sure what this one means either?
meredithl 2016/12/29 06:23:35 Safe Browsing stringify the PermissionType enum, w
133 bool permission_blocked =
134 metadata.api_permissions.find(PermissionUtil::GetPermissionString(
135 permission_type_)) != metadata.api_permissions.end();
136
137 content::BrowserThread::PostTask(
138 content::BrowserThread::UI, FROM_HERE,
139 base::Bind(
140 &PermissionsBlacklistingClient::EvaluateBlacklistResultOnUiThread,
141 this, permission_blocked));
142 }
143
144 void EvaluateBlacklistResultOnUiThread(bool permission_blocked) {
145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
146
147 if (is_active_)
raymes 2016/12/20 23:58:57 It doesn't look like is_active_ is initialized any
meredithl 2016/12/29 06:23:35 Done.
148 callback_.Run(permission_blocked);
149 Release();
150 }
151
152 // WebContentsObserver implementation. Sets the flag so that when the database
153 // manager returns with a result, it won't attempt to run the callback with a
154 // deleted WebContents.
155 void WebContentsDestroyed() override {
156 is_active_ = false;
157 Observe(nullptr);
raymes 2016/12/20 23:58:57 Why is this needed? Is it just so we don't acciden
meredithl 2016/12/29 06:23:35 I believe so. Dominick suggested to put it in, and
158 }
159
160 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager_;
161 content::PermissionType permission_type_;
162
163 // PermissionContextBase callback to run on the UI thread.
164 base::Callback<void(bool)> callback_;
165
166 // Timer to abort the Safe Browsing check if it takes too long. Created and
167 // used on the IO Thread.
168 std::unique_ptr<base::OneShotTimer> timer_;
169
170 // True if |callback_| should be invoked. For instance, if web_contents() is
raymes 2016/12/20 23:58:57 nit: Since the only reason why this would be false
meredithl 2016/12/29 06:23:35 Done.
171 // destroyed, this is set to false.
172 bool is_active_;
173
174 DISALLOW_COPY_AND_ASSIGN(PermissionsBlacklistingClient);
175 };
45 176
46 PermissionContextBase::PermissionContextBase( 177 PermissionContextBase::PermissionContextBase(
47 Profile* profile, 178 Profile* profile,
48 const content::PermissionType permission_type, 179 const content::PermissionType permission_type,
49 const ContentSettingsType content_settings_type) 180 const ContentSettingsType content_settings_type)
50 : profile_(profile), 181 : profile_(profile),
51 permission_type_(permission_type), 182 permission_type_(permission_type),
52 content_settings_type_(content_settings_type), 183 content_settings_type_(content_settings_type),
184 safe_browsing_timeout_(kCheckUrlTimeoutMs),
53 weak_factory_(this) { 185 weak_factory_(this) {
54 #if defined(OS_ANDROID) 186 #if defined(OS_ANDROID)
55 permission_queue_controller_.reset(new PermissionQueueController( 187 permission_queue_controller_.reset(new PermissionQueueController(
56 profile_, permission_type_, content_settings_type_)); 188 profile_, permission_type_, content_settings_type_));
57 #endif 189 #endif
58 PermissionDecisionAutoBlocker::UpdateFromVariations(); 190 PermissionDecisionAutoBlocker::UpdateFromVariations();
59 } 191 }
60 192
61 PermissionContextBase::~PermissionContextBase() { 193 PermissionContextBase::~PermissionContextBase() {
62 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 194 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 226
95 DVLOG(1) << "Attempt to use " << type_name 227 DVLOG(1) << "Attempt to use " << type_name
96 << " from an invalid URL: " << requesting_origin << "," 228 << " from an invalid URL: " << requesting_origin << ","
97 << embedding_origin << " (" << type_name 229 << embedding_origin << " (" << type_name
98 << " is not supported in popups)"; 230 << " is not supported in popups)";
99 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, 231 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback,
100 false /* persist */, CONTENT_SETTING_BLOCK); 232 false /* persist */, CONTENT_SETTING_BLOCK);
101 return; 233 return;
102 } 234 }
103 235
236 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager =
237 db_manager_;
238 if (!db_manager) {
239 safe_browsing::SafeBrowsingService* sb_service =
240 g_browser_process->safe_browsing_service();
241 if (sb_service)
242 db_manager = sb_service->database_manager();
raymes 2016/12/20 23:58:57 Hmm, we never set the instance variable here. I th
meredithl 2016/12/29 06:23:35 Done.
243 }
kcarattini 2016/12/20 19:57:10 Do you need these 8 lines here or can you move the
raymes 2016/12/20 23:58:57 Good thought.
meredithl 2016/12/29 06:23:35 Ooh yep. Good catch. Done.
244
245 if (base::FeatureList::IsEnabled(features::kPermissionsBlacklist) &&
246 db_manager) {
247 // The client contacts Safe Browsing, and runs the callback with the result.
248 PermissionsBlacklistingClient::CheckSafeBrowsingBlacklist(
249 db_manager, permission_type_, requesting_origin, web_contents,
250 safe_browsing_timeout_,
251 base::Bind(&PermissionContextBase::ContinueRequestPermission,
252 weak_factory_.GetWeakPtr(), web_contents, id,
253 requesting_origin, embedding_origin, user_gesture,
254 callback));
255 } else {
256 // TODO(meredithl) : add UMA metrics here.
raymes 2016/12/20 23:58:57 nit: here and elsewhere, no space before : in TODO
meredithl 2016/12/29 06:23:35 Done.
257 ContinueRequestPermission(web_contents, id, requesting_origin,
258 embedding_origin, user_gesture, callback,
259 false /* permission blocked */);
260 }
261 }
262
263 void PermissionContextBase::ContinueRequestPermission(
264 content::WebContents* web_contents,
265 const PermissionRequestID& id,
266 const GURL& requesting_origin,
267 const GURL& embedding_origin,
268 bool user_gesture,
269 const BrowserPermissionCallback& callback,
270 bool permission_blocked) {
271 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
272 if (permission_blocked) {
273 // TODO(meredithl) : add UMA metrics here.
274 web_contents->GetMainFrame()->AddMessageToConsole(
275 content::CONSOLE_MESSAGE_LEVEL_LOG,
276 base::StringPrintf(
277 "%s permission has been auto-blocked.",
278 PermissionUtil::GetPermissionString(permission_type_).c_str()));
279 // Permission has been blacklisted, block the request.
280 // TODO(meredithl) : consider setting the content setting and persisting
281 // the decision to block.
282 callback.Run(CONTENT_SETTING_BLOCK);
283 return;
284 }
285
286 // Site is not blacklisted by Safe Browsing for the requested permission.
104 ContentSetting content_setting = 287 ContentSetting content_setting =
105 GetPermissionStatus(requesting_origin, embedding_origin); 288 GetPermissionStatus(requesting_origin, embedding_origin);
106 if (content_setting == CONTENT_SETTING_ALLOW) { 289 if (content_setting == CONTENT_SETTING_ALLOW) {
107 HostContentSettingsMapFactory::GetForProfile(profile_)->UpdateLastUsage( 290 HostContentSettingsMapFactory::GetForProfile(profile_)->UpdateLastUsage(
108 requesting_origin, embedding_origin, content_settings_type_); 291 requesting_origin, embedding_origin, content_settings_type_);
109 } 292 }
293
110 if (content_setting == CONTENT_SETTING_ALLOW || 294 if (content_setting == CONTENT_SETTING_ALLOW ||
111 content_setting == CONTENT_SETTING_BLOCK) { 295 content_setting == CONTENT_SETTING_BLOCK) {
112 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, 296 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback,
113 false /* persist */, content_setting); 297 false /* persist */, content_setting);
114 return; 298 return;
115 } 299 }
116 300
117 PermissionUmaUtil::PermissionRequested(permission_type_, requesting_origin, 301 PermissionUmaUtil::PermissionRequested(permission_type_, requesting_origin,
118 embedding_origin, profile_); 302 embedding_origin, profile_);
119 303
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 DCHECK(content_setting == CONTENT_SETTING_ALLOW || 500 DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
317 content_setting == CONTENT_SETTING_BLOCK); 501 content_setting == CONTENT_SETTING_BLOCK);
318 DCHECK(!requesting_origin.SchemeIsFile()); 502 DCHECK(!requesting_origin.SchemeIsFile());
319 DCHECK(!embedding_origin.SchemeIsFile()); 503 DCHECK(!embedding_origin.SchemeIsFile());
320 504
321 HostContentSettingsMapFactory::GetForProfile(profile_) 505 HostContentSettingsMapFactory::GetForProfile(profile_)
322 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin, 506 ->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
323 content_settings_type_, std::string(), 507 content_settings_type_, std::string(),
324 content_setting); 508 content_setting);
325 } 509 }
510
511 void PermissionContextBase::SetSafeBrowsingDatabaseManagerForTests(
512 scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager) {
513 db_manager_ = db_manager;
514 }
515
516 void PermissionContextBase::SetTimeoutForSafeBrowsingClient(int timeout) {
517 safe_browsing_timeout_ = timeout;
518 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698