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

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: Addressed first set of comments 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[]{
emaxx 2016/07/26 02:55:31 nit: Please use some consistent style, either " =
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Gone.
29 "kmendfapggjehodndflmmgagdbamhnfd", // Gnubby component extension.
emaxx 2016/07/26 02:55:31 Is this needed? The code below seems to allow the
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Gone.
30 "beknehfpfkghjoafdifaflglpjkojoco", // Gnubby app
emaxx 2016/07/26 02:55:31 Is it confirmed that this app is normally installe
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Gone.
31 "ljoammodoonkhnehlncldjelhidljdpi", // Genius app (help)
emaxx 2016/07/26 02:55:31 This and the next one also seem to be the componen
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Gone. But we explicitly block all component extens
emaxx 2016/08/30 13:01:41 Isn't it possible to allow all component extension
32 "mppnpdlheglhdfmldimlhpnegondlapf", // Virtual Keyboard
33 nullptr // End of list
34 };
35
36 const char* const kSafePermissionStrings[] = {
37 "usb",
emaxx 2016/07/26 02:55:31 nit: Please sort the list lexicographically.
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Gone.
38 "certificateProvider",
39 "storage",
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).
emaxx 2016/07/26 02:55:32 nit: s/ (and for more documentation)// (there's no
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Here and below : Gone.
45 const char* const kSafePermissionDicts[] = {
46 // No dictionary permissions are allowed at the moment.
emaxx 2016/07/26 02:55:31 Actually, we already need "usbDevices" dictionary
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Acknowledged.
47 nullptr // End of list
48 };
49
50 // Checks if this provider applies to given extension.
51 bool IsApplicableForSigninPolicy(const extensions::Extension* extension) {
52 if (extension->location() == extensions::Manifest::COMPONENT) {
emaxx 2016/07/26 02:55:31 Shouldn't EXTERNAL_COMPONENT be also specified her
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Acknowledged.
53 // Do not apply to component extensions.
54 return false;
55 }
56 return true;
emaxx 2016/07/26 02:55:31 Not sure, but it probably also makes sense to alwa
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Acknowledged.
57 }
58
59 // Checks if this provider applies to given extension.
emaxx 2016/07/26 02:55:31 nit: Please fix the comment.
Denis Kuznetsov (DE-MUC) 2016/08/29 15:14:40 Acknowledged.
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()
65 << " is not an application: " << extension->GetType();
66 return true;
67 }
68 if (extension->location() == extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD ||
emaxx 2016/07/26 02:55:31 BTW, there's a function Manifest::IsPolicyLocation
emaxx 2016/07/26 02:55:31 IMO, the logic would be simpler if you would negat
69 extension->location() == extensions::Manifest::EXTERNAL_POLICY) {
70 return false;
71 }
72 LOG(ERROR) << extension->id()
73 << " location is prohibited: " << extension->location();
emaxx 2016/07/26 02:55:32 I haven't found operator<< for Manifest::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) {
emaxx 2016/07/26 02:55:31 You may consider passing the array as a reference
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,
emaxx 2016/07/26 02:55:31 nit: s/Public Sessions/the login screen/ (or signi
88 // which among other things requires the manifest top-level entries to be
89 // contained in the |kSafeManifestEntries| whitelist and all permissions to be
emaxx 2016/07/26 02:55:31 nit: Remove references to kSafeManifestEntries.
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 }
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;
emaxx 2016/07/26 02:55:32 Shouldn't this be "safe = false", as in other simi
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") {
emaxx 2016/07/26 02:55:32 This check would fail for the current versions of
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 if (extension->manifest()->GetManifestVersion() != 2) {
167 LOG(ERROR) << extension->id()
168 << " has non-whitelisted manifest version.";
169 safe = false;
170 continue;
171 }
172 } else {
173 // Everything else is a warning.
emaxx 2016/07/26 02:55:31 Looking at our examples of the login screen apps,
174 LOG(WARNING) << extension->id()
175 << " has non-whitelisted manifest entry: " << entry.key();
176 }
177 }
178 return safe;
179 }
180
181 } // namespace
182
183 SigninScreenPolicyProvider::SigninScreenPolicyProvider() {}
184
185 SigninScreenPolicyProvider::~SigninScreenPolicyProvider() {}
186
187 std::string SigninScreenPolicyProvider::GetDebugPolicyProviderName() const {
188 #if defined(NDEBUG)
189 NOTREACHED();
190 return std::string();
191 #else
192 return "permissions for sign-in screen";
193 #endif
194 }
195
196 bool SigninScreenPolicyProvider::UserMayLoad(
197 const extensions::Extension* extension,
198 base::string16* error) const {
199 if (!IsApplicableForSigninPolicy(extension)) {
200 return true;
201 }
202 if (ArrayContains(kWhitelistedApps, extension->id())) {
203 return true;
204 }
205 // Allow force-installed platform app if all manifest contents are
206 // whitelisted.
207 if (!IsProhibitedForSignin(extension) && IsSafeForSignin(extension)) {
208 return true;
209 }
210 // Disallow all other extensions.
211 if (error) {
212 *error =
213 l10n_util::GetStringFUTF16(IDS_EXTENSION_CANT_INSTALL_ON_LOGIN_SCREEN,
214 base::UTF8ToUTF16(extension->name()),
215 base::UTF8ToUTF16(extension->id()));
216 }
217 return false;
218 }
219
220 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698