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