Upload upstream chromium 94.0.4606.31
[platform/framework/web/chromium-efl.git] / components / permissions / permission_context_base.cc
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 <stddef.h>
8
9 #include <string>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/logging.h"
15 #include "base/metrics/field_trial_params.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/time/time.h"
18 #include "build/build_config.h"
19 #include "components/content_settings/core/browser/content_settings_registry.h"
20 #include "components/content_settings/core/browser/host_content_settings_map.h"
21 #include "components/permissions/features.h"
22 #include "components/permissions/permission_decision_auto_blocker.h"
23 #include "components/permissions/permission_request.h"
24 #include "components/permissions/permission_request_id.h"
25 #include "components/permissions/permission_request_manager.h"
26 #include "components/permissions/permission_uma_util.h"
27 #include "components/permissions/permission_util.h"
28 #include "components/permissions/permissions_client.h"
29 #include "components/permissions/request_type.h"
30 #include "content/public/browser/back_forward_cache.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/global_routing_id.h"
33 #include "content/public/browser/navigation_entry.h"
34 #include "content/public/browser/render_frame_host.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/common/content_features.h"
37 #include "services/network/public/cpp/is_potentially_trustworthy.h"
38 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
39 #include "url/gurl.h"
40
41 namespace permissions {
42 namespace {
43
44 const char kPermissionBlockedKillSwitchMessage[] =
45     "%s permission has been blocked.";
46
47 #if defined(OS_ANDROID)
48 const char kPermissionBlockedRepeatedDismissalsMessage[] =
49     "%s permission has been blocked as the user has dismissed the permission "
50     "prompt several times. This can be reset in Site Settings. See "
51     "https://www.chromestatus.com/features/6443143280984064 for more "
52     "information.";
53
54 const char kPermissionBlockedRepeatedIgnoresMessage[] =
55     "%s permission has been blocked as the user has ignored the permission "
56     "prompt several times. This can be reset in Site Settings. See "
57     "https://www.chromestatus.com/features/6443143280984064 for more "
58     "information.";
59 #else
60 const char kPermissionBlockedRepeatedDismissalsMessage[] =
61     "%s permission has been blocked as the user has dismissed the permission "
62     "prompt several times. This can be reset in Page Info which can be "
63     "accessed by clicking the lock icon next to the URL. See "
64     "https://www.chromestatus.com/features/6443143280984064 for more "
65     "information.";
66
67 const char kPermissionBlockedRepeatedIgnoresMessage[] =
68     "%s permission has been blocked as the user has ignored the permission "
69     "prompt several times. This can be reset in Page Info which can be "
70     "accessed by clicking the lock icon next to the URL. See "
71     "https://www.chromestatus.com/features/6443143280984064 for more "
72     "information.";
73 #endif
74
75 const char kPermissionBlockedPermissionsPolicyMessage[] =
76     "%s permission has been blocked because of a permissions policy applied to"
77     " the current document. See https://goo.gl/EuHzyv for more details.";
78
79 const char kPermissionBlockedPortalsMessage[] =
80     "%s permission has been blocked because it was requested inside a portal. "
81     "Portals don't currently support permission requests.";
82
83 void LogPermissionBlockedMessage(content::WebContents* web_contents,
84                                  const char* message,
85                                  ContentSettingsType type) {
86   web_contents->GetMainFrame()->AddMessageToConsole(
87       blink::mojom::ConsoleMessageLevel::kWarning,
88       base::StringPrintf(message,
89                          PermissionUtil::GetPermissionString(type).c_str()));
90 }
91
92 }  // namespace
93
94 // static
95 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] =
96     "PermissionsKillSwitch";
97 // static
98 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] =
99     "blocked";
100
101 PermissionContextBase::PermissionContextBase(
102     content::BrowserContext* browser_context,
103     ContentSettingsType content_settings_type,
104     blink::mojom::PermissionsPolicyFeature permissions_policy_feature)
105     : browser_context_(browser_context),
106       content_settings_type_(content_settings_type),
107       permissions_policy_feature_(permissions_policy_feature) {
108   PermissionDecisionAutoBlocker::UpdateFromVariations();
109 }
110
111 PermissionContextBase::~PermissionContextBase() {
112   DCHECK(permission_observers_.empty());
113   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
114 }
115
116 void PermissionContextBase::RequestPermission(
117     content::WebContents* web_contents,
118     const PermissionRequestID& id,
119     const GURL& requesting_frame,
120     bool user_gesture,
121     BrowserPermissionCallback callback) {
122   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
123
124   GURL requesting_origin = requesting_frame.GetOrigin();
125   GURL embedding_origin =
126       PermissionUtil::GetLastCommittedOriginAsURL(web_contents);
127
128   if (!requesting_origin.is_valid() || !embedding_origin.is_valid()) {
129     std::string type_name =
130         PermissionUtil::GetPermissionString(content_settings_type_);
131
132     DVLOG(1) << "Attempt to use " << type_name
133              << " from an invalid URL: " << requesting_origin << ","
134              << embedding_origin << " (" << type_name
135              << " is not supported in popups)";
136     NotifyPermissionSet(id, requesting_origin, embedding_origin,
137                         std::move(callback), /*persist=*/false,
138                         CONTENT_SETTING_BLOCK, /*is_one_time=*/false);
139     return;
140   }
141
142   // Check the content setting to see if the user has already made a decision,
143   // or if the origin is under embargo. If so, respect that decision.
144   content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
145       id.render_process_id(), id.render_frame_id());
146   PermissionResult result =
147       GetPermissionStatus(rfh, requesting_origin, embedding_origin);
148
149   if (result.content_setting == CONTENT_SETTING_ALLOW ||
150       result.content_setting == CONTENT_SETTING_BLOCK) {
151     switch (result.source) {
152       case PermissionStatusSource::KILL_SWITCH:
153         // Block the request and log to the developer console.
154         LogPermissionBlockedMessage(web_contents,
155                                     kPermissionBlockedKillSwitchMessage,
156                                     content_settings_type_);
157         std::move(callback).Run(CONTENT_SETTING_BLOCK);
158         return;
159       case PermissionStatusSource::MULTIPLE_DISMISSALS:
160         LogPermissionBlockedMessage(web_contents,
161                                     kPermissionBlockedRepeatedDismissalsMessage,
162                                     content_settings_type_);
163         break;
164       case PermissionStatusSource::MULTIPLE_IGNORES:
165         LogPermissionBlockedMessage(web_contents,
166                                     kPermissionBlockedRepeatedIgnoresMessage,
167                                     content_settings_type_);
168         break;
169       case PermissionStatusSource::FEATURE_POLICY:
170         LogPermissionBlockedMessage(web_contents,
171                                     kPermissionBlockedPermissionsPolicyMessage,
172                                     content_settings_type_);
173         break;
174       case PermissionStatusSource::PORTAL:
175         LogPermissionBlockedMessage(web_contents,
176                                     kPermissionBlockedPortalsMessage,
177                                     content_settings_type_);
178         break;
179       case PermissionStatusSource::INSECURE_ORIGIN:
180       case PermissionStatusSource::UNSPECIFIED:
181       case PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN:
182         break;
183     }
184
185     // If we are under embargo, record the embargo reason for which we have
186     // suppressed the prompt.
187     PermissionUmaUtil::RecordEmbargoPromptSuppressionFromSource(result.source);
188     NotifyPermissionSet(id, requesting_origin, embedding_origin,
189                         std::move(callback), /*persist=*/false,
190                         result.content_setting, /*is_one_time=*/false);
191     return;
192   }
193
194   // Don't show request permission UI for an inactive RenderFrameHost as the
195   // page might not distinguish properly between user denying the permission and
196   // automatic rejection, leading to an inconsistent UX once the page becomes
197   // active again.
198   // - If this is called when RenderFrameHost is in BackForwardCache, evict the
199   // document from the cache.
200   // - If this is called when RenderFrameHost is in prerendering, cancel
201   // prerendering.
202   if (rfh->IsInactiveAndDisallowActivation()) {
203     std::move(callback).Run(result.content_setting);
204     return;
205   }
206
207   // We are going to show a prompt now.
208   PermissionUmaUtil::PermissionRequested(content_settings_type_,
209                                          requesting_origin);
210   PermissionUmaUtil::RecordEmbargoPromptSuppression(
211       PermissionEmbargoStatus::NOT_EMBARGOED);
212
213   DecidePermission(web_contents, id, requesting_origin, embedding_origin,
214                    user_gesture, std::move(callback));
215 }
216
217 void PermissionContextBase::UserMadePermissionDecision(
218     const PermissionRequestID& id,
219     const GURL& requesting_origin,
220     const GURL& embedding_origin,
221     ContentSetting content_setting) {}
222
223 std::unique_ptr<PermissionRequest>
224 PermissionContextBase::CreatePermissionRequest(
225     const GURL& request_origin,
226     ContentSettingsType content_settings_type,
227     bool has_gesture,
228     content::WebContents* web_contents,
229     PermissionRequest::PermissionDecidedCallback permission_decided_callback,
230     base::OnceClosure delete_callback) const {
231   return std::make_unique<PermissionRequest>(
232       request_origin, ContentSettingsTypeToRequestType(content_settings_type),
233       has_gesture, std::move(permission_decided_callback),
234       std::move(delete_callback));
235 }
236
237 PermissionResult PermissionContextBase::GetPermissionStatus(
238     content::RenderFrameHost* render_frame_host,
239     const GURL& requesting_origin,
240     const GURL& embedding_origin) const {
241   // If the permission has been disabled through Finch, block all requests.
242   if (IsPermissionKillSwitchOn()) {
243     return PermissionResult(CONTENT_SETTING_BLOCK,
244                             PermissionStatusSource::KILL_SWITCH);
245   }
246
247   if (!IsPermissionAvailableToOrigins(requesting_origin, embedding_origin)) {
248     return PermissionResult(CONTENT_SETTING_BLOCK,
249                             PermissionStatusSource::INSECURE_ORIGIN);
250   }
251
252   // Check whether the feature is enabled for the frame by permissions policy.
253   // We can only do this when a RenderFrameHost has been provided.
254   if (render_frame_host &&
255       !PermissionAllowedByPermissionsPolicy(render_frame_host)) {
256     return PermissionResult(CONTENT_SETTING_BLOCK,
257                             PermissionStatusSource::FEATURE_POLICY);
258   }
259
260   if (render_frame_host) {
261     content::WebContents* web_contents =
262         content::WebContents::FromRenderFrameHost(render_frame_host);
263
264     // Permissions are denied for portals.
265     if (web_contents && web_contents->IsPortal()) {
266       return PermissionResult(CONTENT_SETTING_BLOCK,
267                               PermissionStatusSource::PORTAL);
268     }
269
270     // Automatically deny all HTTP or HTTPS requests where the virtual URL and
271     // the loaded URL are for different origins. The loaded URL is the one
272     // actually in the renderer, but the virtual URL is the one
273     // seen by the user. This may be very confusing for a user to see in a
274     // permissions request.
275     content::NavigationEntry* entry =
276         web_contents->GetController().GetLastCommittedEntry();
277     if (entry) {
278       const GURL virtual_url = entry->GetVirtualURL();
279       const GURL loaded_url = entry->GetURL();
280       if (virtual_url.SchemeIsHTTPOrHTTPS() &&
281           loaded_url.SchemeIsHTTPOrHTTPS() &&
282           !url::Origin::Create(virtual_url)
283                .IsSameOriginWith(url::Origin::Create(loaded_url))) {
284         return PermissionResult(
285             CONTENT_SETTING_BLOCK,
286             PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN);
287       }
288     }
289   }
290
291   ContentSetting content_setting = GetPermissionStatusInternal(
292       render_frame_host, requesting_origin, embedding_origin);
293
294   if (content_setting != CONTENT_SETTING_ASK) {
295     return PermissionResult(content_setting,
296                             PermissionStatusSource::UNSPECIFIED);
297   }
298
299   PermissionResult result =
300       PermissionsClient::Get()
301           ->GetPermissionDecisionAutoBlocker(browser_context_)
302           ->GetEmbargoResult(requesting_origin, content_settings_type_);
303   DCHECK(result.content_setting == CONTENT_SETTING_ASK ||
304          result.content_setting == CONTENT_SETTING_BLOCK);
305   return result;
306 }
307
308 bool PermissionContextBase::IsPermissionAvailableToOrigins(
309     const GURL& requesting_origin,
310     const GURL& embedding_origin) const {
311   if (IsRestrictedToSecureOrigins()) {
312     if (!network::IsUrlPotentiallyTrustworthy(requesting_origin))
313       return false;
314
315     // TODO(raymes): We should check the entire chain of embedders here whenever
316     // possible as this corresponds to the requirements of the secure contexts
317     // spec and matches what is implemented in blink. Right now we just check
318     // the top level and requesting origins.
319     if (!PermissionsClient::Get()->CanBypassEmbeddingOriginCheck(
320             requesting_origin, embedding_origin) &&
321         !network::IsUrlPotentiallyTrustworthy(embedding_origin)) {
322       return false;
323     }
324   }
325   return true;
326 }
327
328 PermissionResult PermissionContextBase::UpdatePermissionStatusWithDeviceStatus(
329     PermissionResult result,
330     const GURL& requesting_origin,
331     const GURL& embedding_origin) const {
332   return result;
333 }
334
335 void PermissionContextBase::ResetPermission(const GURL& requesting_origin,
336                                             const GURL& embedding_origin) {
337   if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(
338           content_settings_type_)) {
339     return;
340   }
341   PermissionsClient::Get()
342       ->GetSettingsMap(browser_context_)
343       ->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
344                                       content_settings_type_,
345                                       CONTENT_SETTING_DEFAULT);
346 }
347
348 bool PermissionContextBase::IsPermissionKillSwitchOn() const {
349   const std::string param = base::GetFieldTrialParamValue(
350       kPermissionsKillSwitchFieldStudy,
351       PermissionUtil::GetPermissionString(content_settings_type_));
352
353   return param == kPermissionsKillSwitchBlockedValue;
354 }
355
356 ContentSetting PermissionContextBase::GetPermissionStatusInternal(
357     content::RenderFrameHost* render_frame_host,
358     const GURL& requesting_origin,
359     const GURL& embedding_origin) const {
360   return PermissionsClient::Get()
361       ->GetSettingsMap(browser_context_)
362       ->GetContentSetting(requesting_origin, embedding_origin,
363                           content_settings_type_);
364 }
365
366 void PermissionContextBase::DecidePermission(
367     content::WebContents* web_contents,
368     const PermissionRequestID& id,
369     const GURL& requesting_origin,
370     const GURL& embedding_origin,
371     bool user_gesture,
372     BrowserPermissionCallback callback) {
373   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
374
375   // Under permission delegation, when we display a permission prompt, the
376   // origin displayed in the prompt should never differ from the top-level
377   // origin. Storage access API requests are excluded as they are expected to
378   // request permissions from the frame origin needing access.
379   DCHECK(PermissionsClient::Get()->CanBypassEmbeddingOriginCheck(
380              requesting_origin, embedding_origin) ||
381          requesting_origin == embedding_origin ||
382          content_settings_type_ == ContentSettingsType::STORAGE_ACCESS);
383
384   PermissionRequestManager* permission_request_manager =
385       PermissionRequestManager::FromWebContents(web_contents);
386   // TODO(felt): sometimes |permission_request_manager| is null. This check is
387   // meant to prevent crashes. See crbug.com/457091.
388   if (!permission_request_manager)
389     return;
390
391   std::unique_ptr<PermissionRequest> request_ptr = CreatePermissionRequest(
392       requesting_origin, content_settings_type_, user_gesture, web_contents,
393       base::BindOnce(&PermissionContextBase::PermissionDecided,
394                      weak_factory_.GetWeakPtr(), id, requesting_origin,
395                      embedding_origin, std::move(callback)),
396       base::BindOnce(&PermissionContextBase::CleanUpRequest,
397                      weak_factory_.GetWeakPtr(), id));
398   PermissionRequest* request = request_ptr.get();
399
400   bool inserted =
401       pending_requests_
402           .insert(std::make_pair(id.ToString(), std::move(request_ptr)))
403           .second;
404   DCHECK(inserted) << "Duplicate id " << id.ToString();
405
406   content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
407       id.render_process_id(), id.render_frame_id());
408
409   if (!rfh) {
410     request->Cancelled();
411     request->RequestFinished();
412     return;
413   }
414
415   permission_request_manager->AddRequest(rfh, request);
416 }
417
418 void PermissionContextBase::PermissionDecided(
419     const PermissionRequestID& id,
420     const GURL& requesting_origin,
421     const GURL& embedding_origin,
422     BrowserPermissionCallback callback,
423     ContentSetting content_setting,
424     bool is_one_time) {
425   DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
426          content_setting == CONTENT_SETTING_BLOCK ||
427          content_setting == CONTENT_SETTING_DEFAULT);
428   UserMadePermissionDecision(id, requesting_origin, embedding_origin,
429                              content_setting);
430
431   bool persist = content_setting != CONTENT_SETTING_DEFAULT;
432   NotifyPermissionSet(id, requesting_origin, embedding_origin,
433                       std::move(callback), persist, content_setting,
434                       is_one_time);
435 }
436
437 content::BrowserContext* PermissionContextBase::browser_context() const {
438   return browser_context_;
439 }
440
441 void PermissionContextBase::OnContentSettingChanged(
442     const ContentSettingsPattern& primary_pattern,
443     const ContentSettingsPattern& secondary_pattern,
444     ContentSettingsType content_type) {
445   if (content_type != content_settings_type_)
446     return;
447
448   for (permissions::Observer& obs : permission_observers_)
449     obs.OnPermissionChanged(primary_pattern, secondary_pattern, content_type);
450 }
451
452 void PermissionContextBase::AddObserver(
453     permissions::Observer* permission_observer) {
454   if (permission_observers_.empty() &&
455       !content_setting_observer_registered_by_subclass_) {
456     PermissionsClient::Get()
457         ->GetSettingsMap(browser_context_)
458         ->AddObserver(this);
459   }
460   permission_observers_.AddObserver(permission_observer);
461 }
462
463 void PermissionContextBase::RemoveObserver(
464     permissions::Observer* permission_observer) {
465   permission_observers_.RemoveObserver(permission_observer);
466   if (permission_observers_.empty() &&
467       !content_setting_observer_registered_by_subclass_) {
468     PermissionsClient::Get()
469         ->GetSettingsMap(browser_context_)
470         ->RemoveObserver(this);
471   }
472 }
473
474 void PermissionContextBase::NotifyPermissionSet(
475     const PermissionRequestID& id,
476     const GURL& requesting_origin,
477     const GURL& embedding_origin,
478     BrowserPermissionCallback callback,
479     bool persist,
480     ContentSetting content_setting,
481     bool is_one_time) {
482   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
483
484   if (persist) {
485     UpdateContentSetting(requesting_origin, embedding_origin, content_setting,
486                          is_one_time);
487   }
488
489   UpdateTabContext(id, requesting_origin,
490                    content_setting == CONTENT_SETTING_ALLOW);
491
492   if (content_setting == CONTENT_SETTING_DEFAULT)
493     content_setting = CONTENT_SETTING_ASK;
494
495   std::move(callback).Run(content_setting);
496 }
497
498 void PermissionContextBase::CleanUpRequest(const PermissionRequestID& id) {
499   size_t success = pending_requests_.erase(id.ToString());
500   DCHECK(success == 1) << "Missing request " << id.ToString();
501 }
502
503 void PermissionContextBase::UpdateContentSetting(const GURL& requesting_origin,
504                                                  const GURL& embedding_origin,
505                                                  ContentSetting content_setting,
506                                                  bool is_one_time) {
507   DCHECK_EQ(requesting_origin, requesting_origin.GetOrigin());
508   DCHECK_EQ(embedding_origin, embedding_origin.GetOrigin());
509   DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
510          content_setting == CONTENT_SETTING_BLOCK);
511
512   using Constraints = content_settings::ContentSettingConstraints;
513   PermissionsClient::Get()
514       ->GetSettingsMap(browser_context_)
515       ->SetContentSettingDefaultScope(
516           requesting_origin, embedding_origin, content_settings_type_,
517           content_setting,
518           is_one_time ? Constraints{base::Time(),
519                                     content_settings::SessionModel::OneTime}
520                       : Constraints());
521 }
522
523 bool PermissionContextBase::PermissionAllowedByPermissionsPolicy(
524     content::RenderFrameHost* rfh) const {
525   // Some features don't have an associated permissions policy yet. Allow those.
526   if (permissions_policy_feature_ ==
527       blink::mojom::PermissionsPolicyFeature::kNotFound)
528     return true;
529
530   return rfh->IsFeatureEnabled(permissions_policy_feature_);
531 }
532
533 }  // namespace permissions