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

Side by Side Diff: chrome/browser/chromeos/extensions/signin_screen_policy_provider.cc

Issue 2159103006: Add policy provider that would filter extensions/apps allowed on the (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 5 months 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
(Empty)
1 // Copyright 2013 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 "chrome/browser/chromeos/extensions/signin_screen_policy_provider.h"
6
7 #include <stddef.h>
8
9 #include <cstddef>
10 #include <string>
11
12 #include "base/logging.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "extensions/common/extension.h"
17 #include "extensions/common/manifest.h"
18 #include "extensions/common/manifest_constants.h"
19 #include "ui/base/l10n/l10n_util.h"
20
21 namespace chromeos {
22
23 namespace {
24
25 namespace emk = extensions::manifest_keys;
26
27 // Apps/extensions explicitly whitelisted for use on signin screen.
28 const char* const kWhitelistedApps[]{
29 "kmendfapggjehodndflmmgagdbamhnfd", // Gnubby component extension.
30 "beknehfpfkghjoafdifaflglpjkojoco", // Gnubby app
31 "ljoammodoonkhnehlncldjelhidljdpi", // Genius app (help)
32 "mppnpdlheglhdfmldimlhpnegondlapf", // Virtual Keyboard
33 nullptr // End of list
34 };
35
36 const char* const kSafePermissionStrings[] = {
37 "usb",
38 "certificateProvider",
39 "storage",
asargent_no_longer_on_chrome 2016/07/22 00:13:29 You should use APIPermission::ID here instead of s
Denis Kuznetsov (DE-MUC) 2016/07/22 14:37:14 See reasoning below. I agree that we'd better to h
40 nullptr // End of list
41 };
42
43 // Some permissions take the form of a dictionary. See |kSafePermissionStrings|
44 // for permission strings (and for more documentation).
45 const char* const kSafePermissionDicts[] = {
asargent_no_longer_on_chrome 2016/07/22 00:13:29 Same thing here, although I wonder if you should e
46 // No dictionary permissions are allowed at the moment.
47 nullptr // End of list
48 };
49
50 // Checks if given this provider applies to given extension.
asargent_no_longer_on_chrome 2016/07/22 00:13:28 grammar nit: "if given this provider applies to gi
Denis Kuznetsov (DE-MUC) 2016/07/22 14:37:14 Done.
51 bool IsApplicableForSigninPolicy(const extensions::Extension* extension) {
52 if (extension->location() == extensions::Manifest::COMPONENT) {
53 // Do not apply to component extensions.
54 return false;
55 }
56 return true;
57 }
58
59 // Checks if given this provider applies to given extension.
asargent_no_longer_on_chrome 2016/07/22 00:13:29 same grammar nit here
Denis Kuznetsov (DE-MUC) 2016/07/22 14:37:14 Done.
60 bool IsProhibitedForSignin(const extensions::Extension* extension) {
61 if (extension->GetType() != extensions::Manifest::TYPE_HOSTED_APP &&
62 extension->GetType() != extensions::Manifest::TYPE_PLATFORM_APP &&
63 extension->GetType() != extensions::Manifest::TYPE_LEGACY_PACKAGED_APP) {
64 LOG(ERROR) << extension->id()
asargent_no_longer_on_chrome 2016/07/22 00:13:28 https://chromium.googlesource.com/chromium/src/+/m
Denis Kuznetsov (DE-MUC) 2016/07/22 14:37:14 Yes. Because with ChromeOS login screen the extens
asargent_no_longer_on_chrome 2016/07/25 21:27:01 Ok, that makes sense.
65 << " is not an application: " << extension->GetType();
66 return true;
67 }
68 if (extension->location() == extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD ||
69 extension->location() == extensions::Manifest::EXTERNAL_POLICY) {
70 return false;
71 }
72 LOG(ERROR) << extension->id()
73 << " location is prohibited: " << extension->location();
74 return true;
75 }
76
77 // Return true iff |entry| is contained in |char_array|.
78 bool ArrayContains(const char* const char_array[], const std::string& entry) {
79 for (size_t i = 0; char_array[i] != nullptr; ++i) {
80 if (entry == char_array[i]) {
81 return true;
82 }
83 }
84 return false;
85 }
86
87 // Returns true for platform apps that are considered safe for Public Sessions,
88 // which among other things requires the manifest top-level entries to be
89 // contained in the |kSafeManifestEntries| whitelist and all permissions to be
90 // contained in |kSafePermissionStrings| or |kSafePermissionDicts|. Otherwise
91 // returns false and logs all reasons for failure.
92 bool IsSafeForSignin(const extensions::Extension* extension) {
93 bool safe = true;
94 for (base::DictionaryValue::Iterator entry(*extension->manifest()->value());
95 !entry.IsAtEnd(); entry.Advance()) {
96 // Permissions must be whitelisted in |kSafePermissionStrings|.
97 if (entry.key() == emk::kPermissions ||
98 entry.key() == emk::kOptionalPermissions) {
99 const base::ListValue* list_value;
100 if (!entry.value().GetAsList(&list_value)) {
101 LOG(ERROR) << extension->id() << ": " << entry.key()
102 << " is not a list.";
103 safe = false;
104 continue;
105 }
106 for (auto it = list_value->begin(); it != list_value->end(); ++it) {
107 // Try to read as dictionary.
108 const base::DictionaryValue* dict_value;
109 if ((*it)->GetAsDictionary(&dict_value)) {
110 if (dict_value->size() != 1) {
111 LOG(ERROR) << extension->id()
112 << " has dict in permission list with size "
113 << dict_value->size() << ".";
114 safe = false;
115 continue;
116 }
117 for (base::DictionaryValue::Iterator it2(*dict_value); !it2.IsAtEnd();
118 it2.Advance()) {
119 if (!ArrayContains(kSafePermissionDicts, it2.key())) {
120 LOG(ERROR) << extension->id()
121 << " has non-whitelisted dict in permission list: "
122 << it2.key();
123 safe = false;
124 continue;
125 }
126 }
127 continue;
128 }
129 // Try to read as string.
130 std::string permission_string;
131 if (!(*it)->GetAsString(&permission_string)) {
132 LOG(ERROR) << extension->id() << ": " << entry.key()
133 << " contains a token that's neither a string nor a dict.";
134 safe = false;
135 continue;
136 }
asargent_no_longer_on_chrome 2016/07/22 00:13:28 The code in the above couple of blocks seems a lit
Denis Kuznetsov (DE-MUC) 2016/07/22 14:37:14 We do not want to "allow app if it has permission"
asargent_no_longer_on_chrome 2016/07/25 21:27:01 Do you just care about API permissions or other ty
emaxx 2016/07/26 02:55:30 I would agree that the low-level parsing should id
asargent_no_longer_on_chrome 2016/07/27 21:00:14 Yes, one of the reasons I'm arguing for structured
137 // Accept whitelisted permissions.
138 if (ArrayContains(kSafePermissionStrings, permission_string)) {
139 continue;
140 }
141 LOG(ERROR) << extension->id()
142 << " requested non-whitelisted permission: "
143 << permission_string;
144 return false;
145 }
146 // "app" may only contain "background".
147 } else if (entry.key() == emk::kApp) {
148 const base::DictionaryValue* dict_value;
149 if (!entry.value().GetAsDictionary(&dict_value)) {
150 LOG(ERROR) << extension->id() << ": app is not a dictionary.";
151 safe = false;
152 continue;
153 }
154 for (base::DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
155 it.Advance()) {
156 if (it.key() != "background") {
asargent_no_longer_on_chrome 2016/07/22 00:13:28 I have a similar concern here about this being too
Denis Kuznetsov (DE-MUC) 2016/07/22 14:37:14 We want to allow 3rd-party apps on chromeos sign-i
157 LOG(ERROR) << extension->id()
158 << " has non-whitelisted manifest entry: " << entry.key()
159 << "." << it.key();
160 safe = false;
161 continue;
162 }
163 }
164 // Require v2 because that's the only version we understand.
165 } else if (entry.key() == emk::kManifestVersion) {
166 int version;
asargent_no_longer_on_chrome 2016/07/22 00:13:29 Instead of examining the dictionary value from the
Denis Kuznetsov (DE-MUC) 2016/07/22 14:37:14 Done.
167 if (!entry.value().GetAsInteger(&version)) {
168 LOG(ERROR) << extension->id() << ": " << emk::kManifestVersion
169 << " is not an integer.";
170 safe = false;
171 continue;
172 }
173 if (version != 2) {
174 LOG(ERROR) << extension->id()
175 << " has non-whitelisted manifest version.";
176 safe = false;
177 continue;
178 }
179 } else {
180 // Everything else is a warning.
181 LOG(WARNING) << extension->id()
182 << " has non-whitelisted manifest entry: " << entry.key();
183 }
184 }
185 return safe;
186 }
187
188 } // namespace
189
190 SigninScreenPolicyProvider::SigninScreenPolicyProvider() {}
191
192 SigninScreenPolicyProvider::~SigninScreenPolicyProvider() {}
193
194 std::string SigninScreenPolicyProvider::GetDebugPolicyProviderName() const {
195 #if defined(NDEBUG)
196 NOTREACHED();
197 return std::string();
198 #else
199 return "permissions for sign-in screen";
200 #endif
201 }
202
203 bool SigninScreenPolicyProvider::UserMayLoad(
204 const extensions::Extension* extension,
205 base::string16* error) const {
206 if (!IsApplicableForSigninPolicy(extension)) {
207 return true;
208 }
209 if (ArrayContains(kWhitelistedApps, extension->id())) {
210 return true;
211 }
212 // Allow force-installed platform app if all manifest contents are
213 // whitelisted.
214 if (!IsProhibitedForSignin(extension) && IsSafeForSignin(extension)) {
215 return true;
216 }
217 // Disallow all other extensions.
218 if (error) {
219 *error =
220 l10n_util::GetStringFUTF16(IDS_EXTENSION_CANT_INSTALL_ON_LOGIN_SCREEN,
221 base::UTF8ToUTF16(extension->name()),
222 base::UTF8ToUTF16(extension->id()));
223 }
224 return false;
225 }
226
227 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698