Upload upstream chromium 85.0.4183.84
[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_impl.h"
26 #include "components/permissions/permission_request_manager.h"
27 #include "components/permissions/permission_uma_util.h"
28 #include "components/permissions/permission_util.h"
29 #include "components/permissions/permissions_client.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 "content/public/common/origin_util.h"
38 #include "url/gurl.h"
39
40 namespace permissions {
41 namespace {
42
43 const char kPermissionBlockedKillSwitchMessage[] =
44     "%s permission has been blocked.";
45
46 #if defined(OS_ANDROID)
47 const char kPermissionBlockedRepeatedDismissalsMessage[] =
48     "%s permission has been blocked as the user has dismissed the permission "
49     "prompt several times. This can be reset in Site Settings. See "
50     "https://www.chromestatus.com/features/6443143280984064 for more "
51     "information.";
52
53 const char kPermissionBlockedRepeatedIgnoresMessage[] =
54     "%s permission has been blocked as the user has ignored the permission "
55     "prompt several times. This can be reset in Site Settings. See "
56     "https://www.chromestatus.com/features/6443143280984064 for more "
57     "information.";
58 #else
59 const char kPermissionBlockedRepeatedDismissalsMessage[] =
60     "%s permission has been blocked as the user has dismissed the permission "
61     "prompt several times. This can be reset in Page Info which can be "
62     "accessed by clicking the lock icon next to the URL. See "
63     "https://www.chromestatus.com/features/6443143280984064 for more "
64     "information.";
65
66 const char kPermissionBlockedRepeatedIgnoresMessage[] =
67     "%s permission has been blocked as the user has ignored the permission "
68     "prompt several times. This can be reset in Page Info which can be "
69     "accessed by clicking the lock icon next to the URL. See "
70     "https://www.chromestatus.com/features/6443143280984064 for more "
71     "information.";
72 #endif
73
74 const char kPermissionBlockedFeaturePolicyMessage[] =
75     "%s permission has been blocked because of a Feature Policy applied to the "
76     "current document. See https://goo.gl/EuHzyv for more details.";
77
78 const char kPermissionBlockedPortalsMessage[] =
79     "%s permission has been blocked because it was requested inside a portal. "
80     "Portals don't currently support permission requests.";
81
82 void LogPermissionBlockedMessage(content::WebContents* web_contents,
83                                  const char* message,
84                                  ContentSettingsType type) {
85   web_contents->GetMainFrame()->AddMessageToConsole(
86       blink::mojom::ConsoleMessageLevel::kWarning,
87       base::StringPrintf(message,
88                          PermissionUtil::GetPermissionString(type).c_str()));
89 }
90
91 }  // namespace
92
93 // static
94 const char PermissionContextBase::kPermissionsKillSwitchFieldStudy[] =
95     "PermissionsKillSwitch";
96 // static
97 const char PermissionContextBase::kPermissionsKillSwitchBlockedValue[] =
98     "blocked";
99
100 PermissionContextBase::PermissionContextBase(
101     content::BrowserContext* browser_context,
102     ContentSettingsType content_settings_type,
103     blink::mojom::FeaturePolicyFeature feature_policy_feature)
104     : browser_context_(browser_context),
105       content_settings_type_(content_settings_type),
106       feature_policy_feature_(feature_policy_feature) {
107   PermissionDecisionAutoBlocker::UpdateFromVariations();
108 }
109
110 PermissionContextBase::~PermissionContextBase() {
111   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
112 }
113
114 void PermissionContextBase::RequestPermission(
115     content::WebContents* web_contents,
116     const PermissionRequestID& id,
117     const GURL& requesting_frame,
118     bool user_gesture,
119     BrowserPermissionCallback callback) {
120   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
121
122   GURL requesting_origin = requesting_frame.GetOrigin();
123   GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
124
125   if (!requesting_origin.is_valid() || !embedding_origin.is_valid()) {
126     std::string type_name =
127         PermissionUtil::GetPermissionString(content_settings_type_);
128
129     DVLOG(1) << "Attempt to use " << type_name
130              << " from an invalid URL: " << requesting_origin << ","
131              << embedding_origin << " (" << type_name
132              << " is not supported in popups)";
133     NotifyPermissionSet(id, requesting_origin, embedding_origin,
134                         std::move(callback), false /* persist */,
135                         CONTENT_SETTING_BLOCK);
136     return;
137   }
138
139   // Check the content setting to see if the user has already made a decision,
140   // or if the origin is under embargo. If so, respect that decision.
141   content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
142       id.render_process_id(), id.render_frame_id());
143   PermissionResult result =
144       GetPermissionStatus(rfh, requesting_origin, embedding_origin);
145
146   if (result.content_setting == CONTENT_SETTING_ALLOW ||
147       result.content_setting == CONTENT_SETTING_BLOCK) {
148     switch (result.source) {
149       case PermissionStatusSource::KILL_SWITCH:
150         // Block the request and log to the developer console.
151         LogPermissionBlockedMessage(web_contents,
152                                     kPermissionBlockedKillSwitchMessage,
153                                     content_settings_type_);
154         std::move(callback).Run(CONTENT_SETTING_BLOCK);
155         return;
156       case PermissionStatusSource::MULTIPLE_DISMISSALS:
157         LogPermissionBlockedMessage(web_contents,
158                                     kPermissionBlockedRepeatedDismissalsMessage,
159                                     content_settings_type_);
160         break;
161       case PermissionStatusSource::MULTIPLE_IGNORES:
162         LogPermissionBlockedMessage(web_contents,
163                                     kPermissionBlockedRepeatedIgnoresMessage,
164                                     content_settings_type_);
165         break;
166       case PermissionStatusSource::FEATURE_POLICY:
167         LogPermissionBlockedMessage(web_contents,
168                                     kPermissionBlockedFeaturePolicyMessage,
169                                     content_settings_type_);
170         break;
171       case PermissionStatusSource::PORTAL:
172         LogPermissionBlockedMessage(web_contents,
173                                     kPermissionBlockedPortalsMessage,
174                                     content_settings_type_);
175         break;
176       case PermissionStatusSource::INSECURE_ORIGIN:
177       case PermissionStatusSource::UNSPECIFIED:
178       case PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN:
179         break;
180     }
181
182     // If we are under embargo, record the embargo reason for which we have
183     // suppressed the prompt.
184     PermissionUmaUtil::RecordEmbargoPromptSuppressionFromSource(result.source);
185     NotifyPermissionSet(id, requesting_origin, embedding_origin,
186                         std::move(callback), false /* persist */,
187                         result.content_setting);
188     return;
189   }
190
191   // Make sure we do not show a UI for cached documents
192   if (content::BackForwardCache::EvictIfCached(
193           content::GlobalFrameRoutingId(id.render_process_id(),
194                                         id.render_frame_id()),
195           "PermissionContextBase::RequestPermission")) {
196     std::move(callback).Run(result.content_setting);
197     return;
198   }
199
200   // We are going to show a prompt now.
201   PermissionUmaUtil::PermissionRequested(content_settings_type_,
202                                          requesting_origin);
203   PermissionUmaUtil::RecordEmbargoPromptSuppression(
204       PermissionEmbargoStatus::NOT_EMBARGOED);
205
206   DecidePermission(web_contents, id, requesting_origin, embedding_origin,
207                    user_gesture, std::move(callback));
208 }
209
210 void PermissionContextBase::UserMadePermissionDecision(
211     const PermissionRequestID& id,
212     const GURL& requesting_origin,
213     const GURL& embedding_origin,
214     ContentSetting content_setting) {}
215
216 PermissionResult PermissionContextBase::GetPermissionStatus(
217     content::RenderFrameHost* render_frame_host,
218     const GURL& requesting_origin,
219     const GURL& embedding_origin) const {
220   // If the permission has been disabled through Finch, block all requests.
221   if (IsPermissionKillSwitchOn()) {
222     return PermissionResult(CONTENT_SETTING_BLOCK,
223                             PermissionStatusSource::KILL_SWITCH);
224   }
225
226   if (!IsPermissionAvailableToOrigins(requesting_origin, embedding_origin)) {
227     return PermissionResult(CONTENT_SETTING_BLOCK,
228                             PermissionStatusSource::INSECURE_ORIGIN);
229   }
230
231   // Check whether the feature is enabled for the frame by feature policy. We
232   // can only do this when a RenderFrameHost has been provided.
233   if (render_frame_host &&
234       !PermissionAllowedByFeaturePolicy(render_frame_host)) {
235     return PermissionResult(CONTENT_SETTING_BLOCK,
236                             PermissionStatusSource::FEATURE_POLICY);
237   }
238
239   if (render_frame_host) {
240     content::WebContents* web_contents =
241         content::WebContents::FromRenderFrameHost(render_frame_host);
242
243     // Permissions are denied for portals.
244     if (web_contents && web_contents->IsPortal()) {
245       return PermissionResult(CONTENT_SETTING_BLOCK,
246                               PermissionStatusSource::PORTAL);
247     }
248
249     // Automatically deny all HTTP or HTTPS requests where the virtual URL and
250     // the loaded URL are for different origins. The loaded URL is the one
251     // actually in the renderer, but the virtual URL is the one
252     // seen by the user. This may be very confusing for a user to see in a
253     // permissions request.
254     content::NavigationEntry* entry =
255         web_contents->GetController().GetLastCommittedEntry();
256     if (entry) {
257       const GURL virtual_url = entry->GetVirtualURL();
258       const GURL loaded_url = entry->GetURL();
259       if (virtual_url.SchemeIsHTTPOrHTTPS() &&
260           loaded_url.SchemeIsHTTPOrHTTPS() &&
261           !url::Origin::Create(virtual_url)
262                .IsSameOriginWith(url::Origin::Create(loaded_url))) {
263         return PermissionResult(
264             CONTENT_SETTING_BLOCK,
265             PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN);
266       }
267     }
268   }
269
270   ContentSetting content_setting = GetPermissionStatusInternal(
271       render_frame_host, requesting_origin, embedding_origin);
272
273   if (content_setting != CONTENT_SETTING_ASK) {
274     return PermissionResult(content_setting,
275                             PermissionStatusSource::UNSPECIFIED);
276   }
277
278   PermissionResult result =
279       PermissionsClient::Get()
280           ->GetPermissionDecisionAutoBlocker(browser_context_)
281           ->GetEmbargoResult(requesting_origin, content_settings_type_);
282   DCHECK(result.content_setting == CONTENT_SETTING_ASK ||
283          result.content_setting == CONTENT_SETTING_BLOCK);
284   return result;
285 }
286
287 bool PermissionContextBase::IsPermissionAvailableToOrigins(
288     const GURL& requesting_origin,
289     const GURL& embedding_origin) const {
290   if (IsRestrictedToSecureOrigins()) {
291     if (!content::IsOriginSecure(requesting_origin))
292       return false;
293
294     // TODO(raymes): We should check the entire chain of embedders here whenever
295     // possible as this corresponds to the requirements of the secure contexts
296     // spec and matches what is implemented in blink. Right now we just check
297     // the top level and requesting origins.
298     if (!PermissionsClient::Get()->CanBypassEmbeddingOriginCheck(
299             requesting_origin, embedding_origin) &&
300         !content::IsOriginSecure(embedding_origin)) {
301       return false;
302     }
303   }
304   return true;
305 }
306
307 PermissionResult PermissionContextBase::UpdatePermissionStatusWithDeviceStatus(
308     PermissionResult result,
309     const GURL& requesting_origin,
310     const GURL& embedding_origin) const {
311   return result;
312 }
313
314 void PermissionContextBase::ResetPermission(const GURL& requesting_origin,
315                                             const GURL& embedding_origin) {
316   if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(
317           content_settings_type_)) {
318     return;
319   }
320   PermissionsClient::Get()
321       ->GetSettingsMap(browser_context_)
322       ->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
323                                       content_settings_type_, std::string(),
324                                       CONTENT_SETTING_DEFAULT);
325 }
326
327 bool PermissionContextBase::IsPermissionKillSwitchOn() const {
328   const std::string param = base::GetFieldTrialParamValue(
329       kPermissionsKillSwitchFieldStudy,
330       PermissionUtil::GetPermissionString(content_settings_type_));
331
332   return param == kPermissionsKillSwitchBlockedValue;
333 }
334
335 ContentSetting PermissionContextBase::GetPermissionStatusInternal(
336     content::RenderFrameHost* render_frame_host,
337     const GURL& requesting_origin,
338     const GURL& embedding_origin) const {
339   return PermissionsClient::Get()
340       ->GetSettingsMap(browser_context_)
341       ->GetContentSetting(requesting_origin, embedding_origin,
342                           content_settings_type_, std::string());
343 }
344
345 void PermissionContextBase::DecidePermission(
346     content::WebContents* web_contents,
347     const PermissionRequestID& id,
348     const GURL& requesting_origin,
349     const GURL& embedding_origin,
350     bool user_gesture,
351     BrowserPermissionCallback callback) {
352   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
353
354   // Under permission delegation, when we display a permission prompt, the
355   // origin displayed in the prompt should never differ from the top-level
356   // origin. Storage access API requests are excluded as they are expected to
357   // request permissions from the frame origin needing access.
358   DCHECK(!base::FeatureList::IsEnabled(features::kPermissionDelegation) ||
359          PermissionsClient::Get()->CanBypassEmbeddingOriginCheck(
360              requesting_origin, embedding_origin) ||
361          requesting_origin == embedding_origin ||
362          content_settings_type_ == ContentSettingsType::STORAGE_ACCESS);
363
364   PermissionRequestManager* permission_request_manager =
365       PermissionRequestManager::FromWebContents(web_contents);
366   // TODO(felt): sometimes |permission_request_manager| is null. This check is
367   // meant to prevent crashes. See crbug.com/457091.
368   if (!permission_request_manager)
369     return;
370
371   std::unique_ptr<PermissionRequest> request_ptr =
372       std::make_unique<PermissionRequestImpl>(
373           embedding_origin, requesting_origin, content_settings_type_,
374           user_gesture,
375           base::BindOnce(&PermissionContextBase::PermissionDecided,
376                          weak_factory_.GetWeakPtr(), id, requesting_origin,
377                          embedding_origin, std::move(callback)),
378           base::BindOnce(&PermissionContextBase::CleanUpRequest,
379                          weak_factory_.GetWeakPtr(), id));
380   PermissionRequest* request = request_ptr.get();
381
382   bool inserted =
383       pending_requests_
384           .insert(std::make_pair(id.ToString(), std::move(request_ptr)))
385           .second;
386   DCHECK(inserted) << "Duplicate id " << id.ToString();
387   permission_request_manager->AddRequest(request);
388 }
389
390 void PermissionContextBase::PermissionDecided(
391     const PermissionRequestID& id,
392     const GURL& requesting_origin,
393     const GURL& embedding_origin,
394     BrowserPermissionCallback callback,
395     ContentSetting content_setting) {
396   DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
397          content_setting == CONTENT_SETTING_BLOCK ||
398          content_setting == CONTENT_SETTING_DEFAULT);
399   UserMadePermissionDecision(id, requesting_origin, embedding_origin,
400                              content_setting);
401
402   bool persist = content_setting != CONTENT_SETTING_DEFAULT;
403   NotifyPermissionSet(id, requesting_origin, embedding_origin,
404                       std::move(callback), persist, content_setting);
405 }
406
407 content::BrowserContext* PermissionContextBase::browser_context() const {
408   return browser_context_;
409 }
410
411 void PermissionContextBase::NotifyPermissionSet(
412     const PermissionRequestID& id,
413     const GURL& requesting_origin,
414     const GURL& embedding_origin,
415     BrowserPermissionCallback callback,
416     bool persist,
417     ContentSetting content_setting) {
418   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
419
420   if (persist)
421     UpdateContentSetting(requesting_origin, embedding_origin, content_setting);
422
423   UpdateTabContext(id, requesting_origin,
424                    content_setting == CONTENT_SETTING_ALLOW);
425
426   if (content_setting == CONTENT_SETTING_DEFAULT)
427     content_setting = CONTENT_SETTING_ASK;
428
429   std::move(callback).Run(content_setting);
430 }
431
432 void PermissionContextBase::CleanUpRequest(const PermissionRequestID& id) {
433   size_t success = pending_requests_.erase(id.ToString());
434   DCHECK(success == 1) << "Missing request " << id.ToString();
435 }
436
437 void PermissionContextBase::UpdateContentSetting(
438     const GURL& requesting_origin,
439     const GURL& embedding_origin,
440     ContentSetting content_setting) {
441   DCHECK_EQ(requesting_origin, requesting_origin.GetOrigin());
442   DCHECK_EQ(embedding_origin, embedding_origin.GetOrigin());
443   DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
444          content_setting == CONTENT_SETTING_BLOCK);
445   DCHECK(!requesting_origin.SchemeIsFile());
446   DCHECK(!embedding_origin.SchemeIsFile());
447
448   PermissionsClient::Get()
449       ->GetSettingsMap(browser_context_)
450       ->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
451                                       content_settings_type_, std::string(),
452                                       content_setting);
453 }
454
455 bool PermissionContextBase::PermissionAllowedByFeaturePolicy(
456     content::RenderFrameHost* rfh) const {
457   // Some features don't have an associated feature policy yet. Allow those.
458   if (feature_policy_feature_ == blink::mojom::FeaturePolicyFeature::kNotFound)
459     return true;
460
461   return rfh->IsFeatureEnabled(feature_policy_feature_);
462 }
463
464 }  // namespace permissions