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