1 // Copyright (c) 2012 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 <utility>
6
7 #include "base/test/values_test_util.h"
8 #include "base/values.h"
9 #include "extensions/common/manifest_constants.h"
10 #include "extensions/common/manifest_handler_helpers.h"
11 #include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
12 #include "extensions/common/manifest_test.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace extensions {
16
17 namespace keys = manifest_keys;
18 namespace errors = manifest_errors;
19
20 namespace {
21
22 using manifest_handler_helpers::TokenizeDictionaryPath;
23
24 // Produces extension ID = "mdbihdcgjmagbcapkhhkjbbdlkflmbfo".
25 const char kExtensionKey[] =
26 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCV9PlZjcTIXfnlB3HXo50OlM/CnIq0y7jm"
27 "KfPVyStaWsmFB7NaVnqUXoGb9swBDfVnZ6BrupwnxL76TWEJPo+KQMJ6uz0PPdJWi2jQfZiG"
28 "iheDiKH5Gv+dVd67qf7ly8QWW0o8qmFpqBZQpksm1hOGbfsupv9W4c42tMEIicDMLQIDAQAB";
29 const char kAutoApproveNotAllowedWarning[] =
30 "'oauth2.auto_approve' is not allowed for specified extension ID.";
31
32 } // namespace
33
34 class OAuth2ManifestTest : public ManifestTest {
35 protected:
36 enum AutoApproveValue {
37 AUTO_APPROVE_NOT_SET,
38 AUTO_APPROVE_FALSE,
39 AUTO_APPROVE_TRUE,
40 AUTO_APPROVE_INVALID
41 };
42
43 enum ClientIdValue {
44 CLIENT_ID_DEFAULT,
45 CLIENT_ID_NOT_SET,
46 CLIENT_ID_EMPTY
47 };
48
CreateManifest(AutoApproveValue auto_approve,bool extension_id_whitelisted,ClientIdValue client_id)49 base::Value CreateManifest(AutoApproveValue auto_approve,
50 bool extension_id_whitelisted,
51 ClientIdValue client_id) {
52 base::Value manifest = base::test::ParseJson(R"({
53 "name": "test",
54 "version": "0.1",
55 "manifest_version": 2,
56 "oauth2": {
57 "scopes": [ "scope1" ],
58 },
59 })");
60 EXPECT_TRUE(manifest.is_dict());
61 switch (auto_approve) {
62 case AUTO_APPROVE_NOT_SET:
63 break;
64 case AUTO_APPROVE_FALSE:
65 manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
66 base::Value(false));
67 break;
68 case AUTO_APPROVE_TRUE:
69 manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
70 base::Value(true));
71 break;
72 case AUTO_APPROVE_INVALID:
73 manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
74 base::Value("incorrect value"));
75 break;
76 }
77 switch (client_id) {
78 case CLIENT_ID_DEFAULT:
79 manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2ClientId),
80 base::Value("client1"));
81 break;
82 case CLIENT_ID_NOT_SET:
83 break;
84 case CLIENT_ID_EMPTY:
85 manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2ClientId),
86 base::Value(""));
87 }
88 if (extension_id_whitelisted) {
89 manifest.SetPath(TokenizeDictionaryPath(keys::kKey),
90 base::Value(kExtensionKey));
91 }
92 return manifest;
93 }
94 };
95
TEST_F(OAuth2ManifestTest,OAuth2SectionParsing)96 TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
97 base::Value base_manifest(base::Value::Type::DICTIONARY);
98
99 base_manifest.SetPath(TokenizeDictionaryPath(keys::kName),
100 base::Value("test"));
101 base_manifest.SetPath(TokenizeDictionaryPath(keys::kVersion),
102 base::Value("0.1"));
103 base_manifest.SetPath(TokenizeDictionaryPath(keys::kManifestVersion),
104 base::Value(2));
105 base_manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2ClientId),
106 base::Value("client1"));
107 base::Value scopes(base::Value::Type::LIST);
108 scopes.Append(base::Value("scope1"));
109 scopes.Append(base::Value("scope2"));
110 base_manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2Scopes),
111 std::move(scopes));
112
113 // OAuth2 section should be parsed for an extension.
114 {
115 base::Value ext_manifest(base::Value::Type::DICTIONARY);
116 // Lack of "app" section representa an extension. So the base manifest
117 // itself represents an extension.
118 ext_manifest.MergeDictionary(&base_manifest);
119 ext_manifest.SetPath(TokenizeDictionaryPath(keys::kKey),
120 base::Value(kExtensionKey));
121 ext_manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
122 base::Value(true));
123
124 ManifestData manifest(std::move(ext_manifest), "test");
125 scoped_refptr<extensions::Extension> extension =
126 LoadAndExpectSuccess(manifest);
127 EXPECT_TRUE(extension->install_warnings().empty());
128 EXPECT_EQ("client1", OAuth2Info::GetOAuth2Info(extension.get()).client_id);
129 EXPECT_EQ(2U, OAuth2Info::GetOAuth2Info(extension.get()).scopes.size());
130 EXPECT_EQ("scope1", OAuth2Info::GetOAuth2Info(extension.get()).scopes[0]);
131 EXPECT_EQ("scope2", OAuth2Info::GetOAuth2Info(extension.get()).scopes[1]);
132 EXPECT_TRUE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
133 }
134
135 // OAuth2 section should be parsed for a packaged app.
136 {
137 base::Value app_manifest(base::Value::Type::DICTIONARY);
138 app_manifest.SetPath(TokenizeDictionaryPath(keys::kLaunchLocalPath),
139 base::Value("launch.html"));
140 app_manifest.MergeDictionary(&base_manifest);
141
142 ManifestData manifest(std::move(app_manifest), "test");
143 scoped_refptr<extensions::Extension> extension =
144 LoadAndExpectSuccess(manifest);
145 EXPECT_TRUE(extension->install_warnings().empty());
146 EXPECT_EQ("client1", OAuth2Info::GetOAuth2Info(extension.get()).client_id);
147 EXPECT_EQ(2U, OAuth2Info::GetOAuth2Info(extension.get()).scopes.size());
148 EXPECT_EQ("scope1", OAuth2Info::GetOAuth2Info(extension.get()).scopes[0]);
149 EXPECT_EQ("scope2", OAuth2Info::GetOAuth2Info(extension.get()).scopes[1]);
150 EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
151 }
152
153 // OAuth2 section should NOT be parsed for a hosted app.
154 {
155 base::Value app_manifest(base::Value::Type::DICTIONARY);
156 app_manifest.SetPath(TokenizeDictionaryPath(keys::kLaunchWebURL),
157 base::Value("http://www.google.com"));
158 app_manifest.MergeDictionary(&base_manifest);
159
160 ManifestData manifest(std::move(app_manifest), "test");
161 scoped_refptr<extensions::Extension> extension =
162 LoadAndExpectSuccess(manifest);
163 EXPECT_EQ(1U, extension->install_warnings().size());
164 const extensions::InstallWarning& warning =
165 extension->install_warnings()[0];
166 EXPECT_EQ("'oauth2' is only allowed for extensions, legacy packaged apps, "
167 "and packaged apps, but this is a hosted app.",
168 warning.message);
169 EXPECT_EQ("", OAuth2Info::GetOAuth2Info(extension.get()).client_id);
170 EXPECT_TRUE(OAuth2Info::GetOAuth2Info(extension.get()).scopes.empty());
171 EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
172 }
173 }
174
TEST_F(OAuth2ManifestTest,AutoApproveNotSetExtensionNotOnWhitelist)175 TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionNotOnWhitelist) {
176 base::Value ext_manifest =
177 CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_DEFAULT);
178 ManifestData manifest(std::move(ext_manifest), "test");
179 scoped_refptr<extensions::Extension> extension =
180 LoadAndExpectSuccess(manifest);
181 EXPECT_TRUE(extension->install_warnings().empty());
182 EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
183 }
184
TEST_F(OAuth2ManifestTest,AutoApproveFalseExtensionNotOnWhitelist)185 TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionNotOnWhitelist) {
186 base::Value ext_manifest =
187 CreateManifest(AUTO_APPROVE_FALSE, false, CLIENT_ID_DEFAULT);
188 ManifestData manifest(std::move(ext_manifest), "test");
189 scoped_refptr<extensions::Extension> extension =
190 LoadAndExpectSuccess(manifest);
191 EXPECT_EQ(1U, extension->install_warnings().size());
192 const extensions::InstallWarning& warning =
193 extension->install_warnings()[0];
194 EXPECT_EQ(kAutoApproveNotAllowedWarning, warning.message);
195 EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
196 }
197
TEST_F(OAuth2ManifestTest,AutoApproveTrueExtensionNotOnWhitelist)198 TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionNotOnWhitelist) {
199 base::Value ext_manifest =
200 CreateManifest(AUTO_APPROVE_TRUE, false, CLIENT_ID_DEFAULT);
201 ManifestData manifest(std::move(ext_manifest), "test");
202 scoped_refptr<extensions::Extension> extension =
203 LoadAndExpectSuccess(manifest);
204 EXPECT_EQ(1U, extension->install_warnings().size());
205 const extensions::InstallWarning& warning =
206 extension->install_warnings()[0];
207 EXPECT_EQ(kAutoApproveNotAllowedWarning, warning.message);
208 EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
209 }
210
TEST_F(OAuth2ManifestTest,AutoApproveInvalidExtensionNotOnWhitelist)211 TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionNotOnWhitelist) {
212 base::Value ext_manifest =
213 CreateManifest(AUTO_APPROVE_INVALID, false, CLIENT_ID_DEFAULT);
214 ManifestData manifest(std::move(ext_manifest), "test");
215 scoped_refptr<extensions::Extension> extension =
216 LoadAndExpectSuccess(manifest);
217 EXPECT_EQ(1U, extension->install_warnings().size());
218 const extensions::InstallWarning& warning =
219 extension->install_warnings()[0];
220 EXPECT_EQ(kAutoApproveNotAllowedWarning, warning.message);
221 EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
222 }
223
TEST_F(OAuth2ManifestTest,AutoApproveNotSetExtensionOnWhitelist)224 TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionOnWhitelist) {
225 base::Value ext_manifest =
226 CreateManifest(AUTO_APPROVE_NOT_SET, true, CLIENT_ID_DEFAULT);
227 ManifestData manifest(std::move(ext_manifest), "test");
228 scoped_refptr<extensions::Extension> extension =
229 LoadAndExpectSuccess(manifest);
230 EXPECT_TRUE(extension->install_warnings().empty());
231 EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
232 }
233
TEST_F(OAuth2ManifestTest,AutoApproveFalseExtensionOnWhitelist)234 TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionOnWhitelist) {
235 base::Value ext_manifest =
236 CreateManifest(AUTO_APPROVE_FALSE, true, CLIENT_ID_DEFAULT);
237 ManifestData manifest(std::move(ext_manifest), "test");
238 scoped_refptr<extensions::Extension> extension =
239 LoadAndExpectSuccess(manifest);
240 EXPECT_TRUE(extension->install_warnings().empty());
241 EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
242 }
243
TEST_F(OAuth2ManifestTest,AutoApproveTrueExtensionOnWhitelist)244 TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionOnWhitelist) {
245 base::Value ext_manifest =
246 CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_DEFAULT);
247 ManifestData manifest(std::move(ext_manifest), "test");
248 scoped_refptr<extensions::Extension> extension =
249 LoadAndExpectSuccess(manifest);
250 EXPECT_TRUE(extension->install_warnings().empty());
251 EXPECT_TRUE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
252 }
253
TEST_F(OAuth2ManifestTest,AutoApproveInvalidExtensionOnWhitelist)254 TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionOnWhitelist) {
255 base::Value ext_manifest =
256 CreateManifest(AUTO_APPROVE_INVALID, true, CLIENT_ID_DEFAULT);
257 ManifestData manifest(std::move(ext_manifest), "test");
258 std::string error;
259 scoped_refptr<extensions::Extension> extension =
260 LoadExtension(manifest, &error);
261 EXPECT_EQ(
262 "Invalid value for 'oauth2.auto_approve'. Value must be true or false.",
263 error);
264 }
265
TEST_F(OAuth2ManifestTest,InvalidClientId)266 TEST_F(OAuth2ManifestTest, InvalidClientId) {
267 {
268 base::Value ext_manifest =
269 CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_NOT_SET);
270 ManifestData manifest(std::move(ext_manifest), "test");
271 std::string error;
272 LoadAndExpectError(manifest, errors::kInvalidOAuth2ClientId);
273 }
274
275 {
276 base::Value ext_manifest =
277 CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_EMPTY);
278 ManifestData manifest(std::move(ext_manifest), "test");
279 std::string error;
280 LoadAndExpectError(manifest, errors::kInvalidOAuth2ClientId);
281 }
282 }
283
TEST_F(OAuth2ManifestTest,ComponentInvalidClientId)284 TEST_F(OAuth2ManifestTest, ComponentInvalidClientId) {
285 // Component Apps without auto_approve must include a client ID.
286 {
287 base::Value ext_manifest =
288 CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_NOT_SET);
289 ManifestData manifest(std::move(ext_manifest), "test");
290 std::string error;
291 LoadAndExpectError(manifest,
292 errors::kInvalidOAuth2ClientId,
293 extensions::Manifest::COMPONENT);
294 }
295
296 {
297 base::Value ext_manifest =
298 CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_EMPTY);
299 ManifestData manifest(std::move(ext_manifest), "test");
300 std::string error;
301 LoadAndExpectError(manifest,
302 errors::kInvalidOAuth2ClientId,
303 extensions::Manifest::COMPONENT);
304 }
305 }
306
TEST_F(OAuth2ManifestTest,ComponentWithChromeClientId)307 TEST_F(OAuth2ManifestTest, ComponentWithChromeClientId) {
308 {
309 base::Value ext_manifest =
310 CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_NOT_SET);
311 ManifestData manifest(std::move(ext_manifest), "test");
312 scoped_refptr<extensions::Extension> extension =
313 LoadAndExpectSuccess(manifest, extensions::Manifest::COMPONENT);
314 EXPECT_TRUE(OAuth2Info::GetOAuth2Info(extension.get()).client_id.empty());
315 }
316
317 {
318 base::Value ext_manifest =
319 CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_EMPTY);
320 ManifestData manifest(std::move(ext_manifest), "test");
321 scoped_refptr<extensions::Extension> extension =
322 LoadAndExpectSuccess(manifest, extensions::Manifest::COMPONENT);
323 EXPECT_TRUE(OAuth2Info::GetOAuth2Info(extension.get()).client_id.empty());
324 }
325 }
326
TEST_F(OAuth2ManifestTest,ComponentWithStandardClientId)327 TEST_F(OAuth2ManifestTest, ComponentWithStandardClientId) {
328 base::Value ext_manifest =
329 CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_DEFAULT);
330 ManifestData manifest(std::move(ext_manifest), "test");
331 scoped_refptr<extensions::Extension> extension =
332 LoadAndExpectSuccess(manifest, extensions::Manifest::COMPONENT);
333 EXPECT_EQ("client1", OAuth2Info::GetOAuth2Info(extension.get()).client_id);
334 }
335
336 } // namespace extensions
337