OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 <vector> | 5 #include <vector> |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/memory/ref_counted.h" | 8 #include "base/memory/ref_counted.h" |
9 #include "base/strings/string16.h" | 9 #include "base/strings/string16.h" |
| 10 #include "base/strings/stringprintf.h" |
10 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
11 #include "chrome/common/chrome_version_info.h" | 12 #include "chrome/common/chrome_version_info.h" |
12 #include "chrome/common/extensions/extension_test_util.h" | 13 #include "chrome/common/extensions/extension_test_util.h" |
13 #include "chrome/common/extensions/features/feature_channel.h" | 14 #include "chrome/common/extensions/features/feature_channel.h" |
14 #include "content/public/common/socket_permission_request.h" | 15 #include "content/public/common/socket_permission_request.h" |
15 #include "extensions/common/error_utils.h" | 16 #include "extensions/common/error_utils.h" |
16 #include "extensions/common/extension.h" | 17 #include "extensions/common/extension.h" |
17 #include "extensions/common/extension_builder.h" | 18 #include "extensions/common/extension_builder.h" |
| 19 #include "extensions/common/feature_switch.h" |
18 #include "extensions/common/id_util.h" | 20 #include "extensions/common/id_util.h" |
19 #include "extensions/common/manifest.h" | 21 #include "extensions/common/manifest.h" |
20 #include "extensions/common/manifest_constants.h" | 22 #include "extensions/common/manifest_constants.h" |
21 #include "extensions/common/permissions/api_permission.h" | 23 #include "extensions/common/permissions/api_permission.h" |
22 #include "extensions/common/permissions/permission_set.h" | 24 #include "extensions/common/permissions/permission_set.h" |
23 #include "extensions/common/permissions/permissions_data.h" | 25 #include "extensions/common/permissions/permissions_data.h" |
24 #include "extensions/common/permissions/socket_permission.h" | 26 #include "extensions/common/permissions/socket_permission.h" |
25 #include "extensions/common/switches.h" | 27 #include "extensions/common/switches.h" |
26 #include "extensions/common/url_pattern_set.h" | 28 #include "extensions/common/url_pattern_set.h" |
27 #include "extensions/common/value_builder.h" | 29 #include "extensions/common/value_builder.h" |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 .Set("description", "an extension") | 69 .Set("description", "an extension") |
68 .Set("manifest_version", 2) | 70 .Set("manifest_version", 2) |
69 .Set("version", "1.0.0") | 71 .Set("version", "1.0.0") |
70 .Set("permissions", permissions.Pass()) | 72 .Set("permissions", permissions.Pass()) |
71 .Build()) | 73 .Build()) |
72 .SetLocation(location) | 74 .SetLocation(location) |
73 .SetID(id) | 75 .SetID(id) |
74 .Build(); | 76 .Build(); |
75 } | 77 } |
76 | 78 |
77 bool RequiresActionForScriptExecution(const std::string& extension_id, | |
78 const std::string& host_permissions, | |
79 Manifest::Location location) { | |
80 scoped_refptr<const Extension> extension = | |
81 GetExtensionWithHostPermission(extension_id, | |
82 host_permissions, | |
83 location); | |
84 return extension->permissions_data()->RequiresActionForScriptExecution( | |
85 extension, | |
86 -1, // Ignore tab id for these. | |
87 GURL::EmptyGURL()); | |
88 } | |
89 | |
90 // Checks that urls are properly restricted for the given extension. | 79 // Checks that urls are properly restricted for the given extension. |
91 void CheckRestrictedUrls(const Extension* extension, | 80 void CheckRestrictedUrls(const Extension* extension, |
92 bool block_chrome_urls) { | 81 bool block_chrome_urls) { |
93 // We log the name so we know _which_ extension failed here. | 82 // We log the name so we know _which_ extension failed here. |
94 const std::string& name = extension->name(); | 83 const std::string& name = extension->name(); |
95 const GURL chrome_settings_url("chrome://settings/"); | 84 const GURL chrome_settings_url("chrome://settings/"); |
96 const GURL chrome_extension_url("chrome-extension://foo/bar.html"); | 85 const GURL chrome_extension_url("chrome-extension://foo/bar.html"); |
97 const GURL google_url("https://www.google.com/"); | 86 const GURL google_url("https://www.google.com/"); |
98 const GURL self_url("chrome-extension://" + extension->id() + "/foo.html"); | 87 const GURL self_url("chrome-extension://" + extension->id() + "/foo.html"); |
99 const GURL invalid_url("chrome-debugger://foo/bar.html"); | 88 const GURL invalid_url("chrome-debugger://foo/bar.html"); |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 extension, SocketPermissionRequest::UDP_BIND, "", 8888)); | 248 extension, SocketPermissionRequest::UDP_BIND, "", 8888)); |
260 | 249 |
261 EXPECT_FALSE(CheckSocketPermission( | 250 EXPECT_FALSE(CheckSocketPermission( |
262 extension, SocketPermissionRequest::UDP_SEND_TO, "example.com", 1900)); | 251 extension, SocketPermissionRequest::UDP_SEND_TO, "example.com", 1900)); |
263 EXPECT_TRUE(CheckSocketPermission( | 252 EXPECT_TRUE(CheckSocketPermission( |
264 extension, | 253 extension, |
265 SocketPermissionRequest::UDP_SEND_TO, | 254 SocketPermissionRequest::UDP_SEND_TO, |
266 "239.255.255.250", 1900)); | 255 "239.255.255.250", 1900)); |
267 } | 256 } |
268 | 257 |
269 TEST(ExtensionPermissionsTest, RequiresActionForScriptExecution) { | |
270 // Extensions with all_hosts should require action. | |
271 EXPECT_TRUE(RequiresActionForScriptExecution( | |
272 "all_hosts_permissions", kAllHostsPermission, Manifest::INTERNAL)); | |
273 // Extensions with nearly all hosts are treated the same way. | |
274 EXPECT_TRUE(RequiresActionForScriptExecution( | |
275 "pseudo_all_hosts_permissions", "*://*.com/*", Manifest::INTERNAL)); | |
276 // Extensions with explicit permissions shouldn't require action. | |
277 EXPECT_FALSE(RequiresActionForScriptExecution( | |
278 "explicit_permissions", "https://www.google.com/*", Manifest::INTERNAL)); | |
279 // Policy extensions are exempt... | |
280 EXPECT_FALSE(RequiresActionForScriptExecution( | |
281 "policy", kAllHostsPermission, Manifest::EXTERNAL_POLICY)); | |
282 // ... as are component extensions. | |
283 EXPECT_FALSE(RequiresActionForScriptExecution( | |
284 "component", kAllHostsPermission, Manifest::COMPONENT)); | |
285 // Throw in an external pref extension to make sure that it's not just working | |
286 // for everything non-internal. | |
287 EXPECT_TRUE(RequiresActionForScriptExecution( | |
288 "external_pref", kAllHostsPermission, Manifest::EXTERNAL_PREF)); | |
289 | |
290 // If we grant an extension tab permissions, then it should no longer require | |
291 // action. | |
292 scoped_refptr<const Extension> extension = | |
293 GetExtensionWithHostPermission("all_hosts_permissions", | |
294 kAllHostsPermission, | |
295 Manifest::INTERNAL); | |
296 URLPatternSet allowed_hosts; | |
297 allowed_hosts.AddPattern( | |
298 URLPattern(URLPattern::SCHEME_HTTPS, "https://www.google.com/*")); | |
299 scoped_refptr<PermissionSet> tab_permissions( | |
300 new PermissionSet(APIPermissionSet(), | |
301 ManifestPermissionSet(), | |
302 allowed_hosts, | |
303 URLPatternSet())); | |
304 extension->permissions_data()->UpdateTabSpecificPermissions(0, | |
305 tab_permissions); | |
306 EXPECT_FALSE(extension->permissions_data()->RequiresActionForScriptExecution( | |
307 extension, 0, GURL("https://www.google.com/"))); | |
308 } | |
309 | |
310 TEST(ExtensionPermissionsTest, IsRestrictedUrl) { | 258 TEST(ExtensionPermissionsTest, IsRestrictedUrl) { |
311 scoped_refptr<const Extension> extension = | 259 scoped_refptr<const Extension> extension = |
312 GetExtensionWithHostPermission("normal_extension", | 260 GetExtensionWithHostPermission("normal_extension", |
313 kAllHostsPermission, | 261 kAllHostsPermission, |
314 Manifest::INTERNAL); | 262 Manifest::INTERNAL); |
315 // Chrome urls should be blocked for normal extensions. | 263 // Chrome urls should be blocked for normal extensions. |
316 CheckRestrictedUrls(extension, true); | 264 CheckRestrictedUrls(extension, true); |
317 | 265 |
318 scoped_refptr<const Extension> component = | 266 scoped_refptr<const Extension> component = |
319 GetExtensionWithHostPermission("component", | 267 GetExtensionWithHostPermission("component", |
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 EXPECT_TRUE(ScriptAllowedExclusivelyOnTab(extension.get(), no_urls, 2)); | 747 EXPECT_TRUE(ScriptAllowedExclusivelyOnTab(extension.get(), no_urls, 2)); |
800 | 748 |
801 permissions_data->ClearTabSpecificPermissions(1); | 749 permissions_data->ClearTabSpecificPermissions(1); |
802 EXPECT_FALSE(permissions_data->GetTabSpecificPermissionsForTesting(1)); | 750 EXPECT_FALSE(permissions_data->GetTabSpecificPermissionsForTesting(1)); |
803 | 751 |
804 EXPECT_TRUE(ScriptAllowedExclusivelyOnTab(extension.get(), no_urls, 0)); | 752 EXPECT_TRUE(ScriptAllowedExclusivelyOnTab(extension.get(), no_urls, 0)); |
805 EXPECT_TRUE(ScriptAllowedExclusivelyOnTab(extension.get(), no_urls, 1)); | 753 EXPECT_TRUE(ScriptAllowedExclusivelyOnTab(extension.get(), no_urls, 1)); |
806 EXPECT_TRUE(ScriptAllowedExclusivelyOnTab(extension.get(), no_urls, 2)); | 754 EXPECT_TRUE(ScriptAllowedExclusivelyOnTab(extension.get(), no_urls, 2)); |
807 } | 755 } |
808 | 756 |
| 757 namespace { |
| 758 |
| 759 scoped_refptr<const Extension> CreateExtensionWithPermissions( |
| 760 const std::set<URLPattern>& scriptable_hosts, |
| 761 const std::set<URLPattern>& explicit_hosts, |
| 762 Manifest::Location location) { |
| 763 ListBuilder scriptable_host_list; |
| 764 for (std::set<URLPattern>::const_iterator pattern = scriptable_hosts.begin(); |
| 765 pattern != scriptable_hosts.end(); |
| 766 ++pattern) { |
| 767 scriptable_host_list.Append(pattern->GetAsString()); |
| 768 } |
| 769 |
| 770 ListBuilder explicit_host_list; |
| 771 for (std::set<URLPattern>::const_iterator pattern = explicit_hosts.begin(); |
| 772 pattern != explicit_hosts.end(); |
| 773 ++pattern) { |
| 774 explicit_host_list.Append(pattern->GetAsString()); |
| 775 } |
| 776 |
| 777 DictionaryBuilder script; |
| 778 script.Set("matches", scriptable_host_list.Pass()) |
| 779 .Set("js", ListBuilder().Append("foo.js")); |
| 780 |
| 781 return ExtensionBuilder() |
| 782 .SetLocation(location) |
| 783 .SetManifest( |
| 784 DictionaryBuilder() |
| 785 .Set("name", "extension") |
| 786 .Set("description", "foo") |
| 787 .Set("manifest_version", 2) |
| 788 .Set("version", "0.1.2.3") |
| 789 .Set("content_scripts", ListBuilder().Append(script.Pass())) |
| 790 .Set("permissions", explicit_host_list.Pass())) |
| 791 .Build(); |
| 792 } |
| 793 |
| 794 testing::AssertionResult SetsAreEqual(const std::set<URLPattern>& set1, |
| 795 const std::set<URLPattern>& set2) { |
| 796 // Take the (set1 - set2) U (set2 - set1). This is then the set of all |
| 797 // elements which are in either set1 or set2, but not both. |
| 798 // If the sets are equal, this is none. |
| 799 std::set<URLPattern> difference = base::STLSetUnion<std::set<URLPattern> >( |
| 800 base::STLSetDifference<std::set<URLPattern> >(set1, set2), |
| 801 base::STLSetDifference<std::set<URLPattern> >(set2, set1)); |
| 802 |
| 803 std::string error; |
| 804 for (std::set<URLPattern>::const_iterator iter = difference.begin(); |
| 805 iter != difference.end(); |
| 806 ++iter) { |
| 807 if (iter->GetAsString() == "chrome://favicon/*") |
| 808 continue; // Grr... This is auto-added for extensions with <all_urls> |
| 809 error = base::StringPrintf("%s\n%s contains %s and the other does not.", |
| 810 error.c_str(), |
| 811 (set1.count(*iter) ? "Set1" : "Set2"), |
| 812 iter->GetAsString().c_str()); |
| 813 } |
| 814 |
| 815 if (!error.empty()) |
| 816 return testing::AssertionFailure() << error; |
| 817 return testing::AssertionSuccess(); |
| 818 } |
| 819 |
| 820 } // namespace |
| 821 |
| 822 TEST(PermissionsDataWithheldPermissionsTest, WithholdAllHosts) { |
| 823 // Permissions are only withheld with the appropriate switch turned on. |
| 824 scoped_ptr<FeatureSwitch::ScopedOverride> switch_override( |
| 825 new FeatureSwitch::ScopedOverride( |
| 826 FeatureSwitch::scripts_require_action(), |
| 827 FeatureSwitch::OVERRIDE_ENABLED)); |
| 828 |
| 829 URLPattern google(URLPattern::SCHEME_ALL, "http://www.google.com/*"); |
| 830 URLPattern sub_google(URLPattern::SCHEME_ALL, "http://*.google.com/*"); |
| 831 URLPattern all_http(URLPattern::SCHEME_ALL, "http://*/*"); |
| 832 URLPattern all_hosts(URLPattern::SCHEME_ALL, "<all_urls>"); |
| 833 URLPattern all_com(URLPattern::SCHEME_ALL, "http://*.com/*"); |
| 834 |
| 835 std::set<URLPattern> all_host_patterns; |
| 836 std::set<URLPattern> safe_patterns; |
| 837 |
| 838 all_host_patterns.insert(all_http); |
| 839 all_host_patterns.insert(all_hosts); |
| 840 all_host_patterns.insert(all_com); |
| 841 |
| 842 safe_patterns.insert(google); |
| 843 safe_patterns.insert(sub_google); |
| 844 |
| 845 std::set<URLPattern> all_patterns = base::STLSetUnion<std::set<URLPattern> >( |
| 846 all_host_patterns, safe_patterns); |
| 847 |
| 848 scoped_refptr<const Extension> extension = CreateExtensionWithPermissions( |
| 849 all_patterns, all_patterns, Manifest::INTERNAL); |
| 850 const PermissionsData* permissions_data = extension->permissions_data(); |
| 851 |
| 852 // At first, the active permissions should have only the safe patterns and |
| 853 // the withheld permissions should have only the all host patterns. |
| 854 EXPECT_TRUE(SetsAreEqual( |
| 855 permissions_data->active_permissions()->scriptable_hosts().patterns(), |
| 856 safe_patterns)); |
| 857 EXPECT_TRUE(SetsAreEqual( |
| 858 permissions_data->active_permissions()->explicit_hosts().patterns(), |
| 859 safe_patterns)); |
| 860 EXPECT_TRUE(SetsAreEqual( |
| 861 permissions_data->withheld_permissions()->scriptable_hosts().patterns(), |
| 862 all_host_patterns)); |
| 863 EXPECT_TRUE(SetsAreEqual( |
| 864 permissions_data->withheld_permissions()->explicit_hosts().patterns(), |
| 865 all_host_patterns)); |
| 866 |
| 867 // Then, we grant the withheld all-hosts permissions. |
| 868 permissions_data->GrantWithheldAllHosts(); |
| 869 // Now, active permissions should have all patterns, and withheld permissions |
| 870 // should have none. |
| 871 EXPECT_TRUE(SetsAreEqual( |
| 872 permissions_data->active_permissions()->scriptable_hosts().patterns(), |
| 873 all_patterns)); |
| 874 EXPECT_TRUE(permissions_data->withheld_permissions() |
| 875 ->scriptable_hosts() |
| 876 .patterns() |
| 877 .empty()); |
| 878 EXPECT_TRUE(SetsAreEqual( |
| 879 permissions_data->active_permissions()->explicit_hosts().patterns(), |
| 880 all_patterns)); |
| 881 EXPECT_TRUE(permissions_data->withheld_permissions() |
| 882 ->explicit_hosts() |
| 883 .patterns() |
| 884 .empty()); |
| 885 |
| 886 // Finally, we revoke the all hosts permissions. |
| 887 permissions_data->WithholdAllHosts(); |
| 888 |
| 889 // We should be back to our initial state - all_hosts should be withheld, and |
| 890 // the safe patterns should be granted. |
| 891 EXPECT_TRUE(SetsAreEqual( |
| 892 permissions_data->active_permissions()->scriptable_hosts().patterns(), |
| 893 safe_patterns)); |
| 894 EXPECT_TRUE(SetsAreEqual( |
| 895 permissions_data->active_permissions()->explicit_hosts().patterns(), |
| 896 safe_patterns)); |
| 897 EXPECT_TRUE(SetsAreEqual( |
| 898 permissions_data->withheld_permissions()->scriptable_hosts().patterns(), |
| 899 all_host_patterns)); |
| 900 EXPECT_TRUE(SetsAreEqual( |
| 901 permissions_data->withheld_permissions()->explicit_hosts().patterns(), |
| 902 all_host_patterns)); |
| 903 |
| 904 // Creating a component extension should result in no withheld permissions. |
| 905 extension = CreateExtensionWithPermissions( |
| 906 all_patterns, all_patterns, Manifest::COMPONENT); |
| 907 permissions_data = extension->permissions_data(); |
| 908 EXPECT_TRUE(SetsAreEqual( |
| 909 permissions_data->active_permissions()->scriptable_hosts().patterns(), |
| 910 all_patterns)); |
| 911 EXPECT_TRUE(permissions_data->withheld_permissions() |
| 912 ->scriptable_hosts() |
| 913 .patterns() |
| 914 .empty()); |
| 915 EXPECT_TRUE(SetsAreEqual( |
| 916 permissions_data->active_permissions()->explicit_hosts().patterns(), |
| 917 all_patterns)); |
| 918 EXPECT_TRUE(permissions_data->withheld_permissions() |
| 919 ->explicit_hosts() |
| 920 .patterns() |
| 921 .empty()); |
| 922 |
| 923 // Without the switch, we shouldn't withhold anything. |
| 924 switch_override.reset(); |
| 925 extension = CreateExtensionWithPermissions( |
| 926 all_patterns, all_patterns, Manifest::INTERNAL); |
| 927 permissions_data = extension->permissions_data(); |
| 928 EXPECT_TRUE(SetsAreEqual( |
| 929 permissions_data->active_permissions()->scriptable_hosts().patterns(), |
| 930 all_patterns)); |
| 931 EXPECT_TRUE(permissions_data->withheld_permissions() |
| 932 ->scriptable_hosts() |
| 933 .patterns() |
| 934 .empty()); |
| 935 EXPECT_TRUE(SetsAreEqual( |
| 936 permissions_data->active_permissions()->explicit_hosts().patterns(), |
| 937 all_patterns)); |
| 938 EXPECT_TRUE(permissions_data->withheld_permissions() |
| 939 ->explicit_hosts() |
| 940 .patterns() |
| 941 .empty()); |
| 942 } |
| 943 |
809 } // namespace extensions | 944 } // namespace extensions |
OLD | NEW |