blob: 77e93b3aca133e989dd73acb7e89f13166d70425 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <utility>
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "extensions/common/api/oauth2.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handler_helpers.h"
#include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
#include "extensions/common/manifest_test.h"
#include "extensions/common/mojom/manifest.mojom-shared.h"
#include "testing/gtest/include/gtest/gtest.h"
using extensions::api::oauth2::OAuth2Info;
using extensions::mojom::ManifestLocation;
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
namespace {
using manifest_handler_helpers::TokenizeDictionaryPath;
// Produces extension ID = "mdbihdcgjmagbcapkhhkjbbdlkflmbfo".
const char kExtensionKey[] =
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCV9PlZjcTIXfnlB3HXo50OlM/CnIq0y7jm"
"KfPVyStaWsmFB7NaVnqUXoGb9swBDfVnZ6BrupwnxL76TWEJPo+KQMJ6uz0PPdJWi2jQfZiG"
"iheDiKH5Gv+dVd67qf7ly8QWW0o8qmFpqBZQpksm1hOGbfsupv9W4c42tMEIicDMLQIDAQAB";
const char kAutoApproveNotAllowedWarning[] =
"'oauth2.auto_approve' is not allowed for specified extension ID.";
std::vector<base::StringPiece> GetOauth2KeyPath(base::StringPiece sub_key) {
return std::vector<base::StringPiece>(
{api::oauth2::ManifestKeys::kOauth2, sub_key});
}
} // namespace
class OAuth2ManifestTest : public ManifestTest {
protected:
enum AutoApproveValue {
AUTO_APPROVE_NOT_SET,
AUTO_APPROVE_FALSE,
AUTO_APPROVE_TRUE,
AUTO_APPROVE_INVALID
};
enum ClientIdValue {
CLIENT_ID_DEFAULT,
CLIENT_ID_NOT_SET,
CLIENT_ID_EMPTY
};
base::Value CreateManifest(AutoApproveValue auto_approve,
bool extension_id_whitelisted,
ClientIdValue client_id) {
base::Value manifest = base::test::ParseJson(R"({
"name": "test",
"version": "0.1",
"manifest_version": 2,
"oauth2": {
"scopes": [ "scope1" ],
},
})");
EXPECT_TRUE(manifest.is_dict());
switch (auto_approve) {
case AUTO_APPROVE_NOT_SET:
break;
case AUTO_APPROVE_FALSE:
manifest.SetPath(GetOauth2KeyPath(OAuth2Info::kAutoApprove),
base::Value(false));
break;
case AUTO_APPROVE_TRUE:
manifest.SetPath(GetOauth2KeyPath(OAuth2Info::kAutoApprove),
base::Value(true));
break;
case AUTO_APPROVE_INVALID:
manifest.SetPath(GetOauth2KeyPath(OAuth2Info::kAutoApprove),
base::Value("incorrect value"));
break;
}
switch (client_id) {
case CLIENT_ID_DEFAULT:
manifest.SetPath(GetOauth2KeyPath(OAuth2Info::kClientId),
base::Value("client1"));
break;
case CLIENT_ID_NOT_SET:
break;
case CLIENT_ID_EMPTY:
manifest.SetPath(GetOauth2KeyPath(OAuth2Info::kClientId),
base::Value(""));
}
if (extension_id_whitelisted) {
manifest.SetPath(TokenizeDictionaryPath(keys::kKey),
base::Value(kExtensionKey));
}
return manifest;
}
};
TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
base::Value base_manifest(base::Value::Type::DICTIONARY);
base_manifest.SetPath(TokenizeDictionaryPath(keys::kName),
base::Value("test"));
base_manifest.SetPath(TokenizeDictionaryPath(keys::kVersion),
base::Value("0.1"));
base_manifest.SetPath(TokenizeDictionaryPath(keys::kManifestVersion),
base::Value(2));
base_manifest.SetPath(GetOauth2KeyPath(OAuth2Info::kClientId),
base::Value("client1"));
base::Value scopes(base::Value::Type::LIST);
scopes.Append(base::Value("scope1"));
scopes.Append(base::Value("scope2"));
base_manifest.SetPath(GetOauth2KeyPath(OAuth2Info::kScopes),
std::move(scopes));
// OAuth2 section should be parsed for an extension.
{
base::Value ext_manifest(base::Value::Type::DICTIONARY);
// Lack of "app" section representa an extension. So the base manifest
// itself represents an extension.
ext_manifest.MergeDictionary(&base_manifest);
ext_manifest.SetPath(TokenizeDictionaryPath(keys::kKey),
base::Value(kExtensionKey));
ext_manifest.SetPath(GetOauth2KeyPath(OAuth2Info::kAutoApprove),
base::Value(true));
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_TRUE(extension->install_warnings().empty());
const auto& info = OAuth2ManifestHandler::GetOAuth2Info(*extension);
ASSERT_TRUE(info.client_id);
EXPECT_EQ("client1", *info.client_id);
EXPECT_THAT(info.scopes, ::testing::ElementsAre("scope1", "scope2"));
EXPECT_TRUE(info.auto_approve);
EXPECT_TRUE(*info.auto_approve);
}
// OAuth2 section should be parsed for a packaged app.
{
base::Value app_manifest(base::Value::Type::DICTIONARY);
app_manifest.SetPath(TokenizeDictionaryPath(keys::kLaunchLocalPath),
base::Value("launch.html"));
app_manifest.MergeDictionary(&base_manifest);
ManifestData manifest(std::move(app_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_TRUE(extension->install_warnings().empty());
const auto& info = OAuth2ManifestHandler::GetOAuth2Info(*extension);
ASSERT_TRUE(info.client_id);
EXPECT_EQ("client1", *info.client_id);
EXPECT_THAT(info.scopes, ::testing::ElementsAre("scope1", "scope2"));
EXPECT_FALSE(info.auto_approve);
}
// OAuth2 section should NOT be parsed for a hosted app.
{
base::Value app_manifest(base::Value::Type::DICTIONARY);
app_manifest.SetPath(TokenizeDictionaryPath(keys::kLaunchWebURL),
base::Value("http://www.google.com"));
app_manifest.MergeDictionary(&base_manifest);
ManifestData manifest(std::move(app_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_EQ(1U, extension->install_warnings().size());
const extensions::InstallWarning& warning =
extension->install_warnings()[0];
EXPECT_EQ("'oauth2' is only allowed for extensions, legacy packaged apps, "
"and packaged apps, but this is a hosted app.",
warning.message);
const auto& info = OAuth2ManifestHandler::GetOAuth2Info(*extension);
EXPECT_FALSE(info.client_id);
EXPECT_TRUE(info.scopes.empty());
EXPECT_FALSE(info.auto_approve);
}
}
TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionNotOnWhitelist) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_TRUE(extension->install_warnings().empty());
EXPECT_FALSE(OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
}
TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionNotOnWhitelist) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_FALSE, false, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_EQ(1U, extension->install_warnings().size());
const extensions::InstallWarning& warning =
extension->install_warnings()[0];
EXPECT_EQ(kAutoApproveNotAllowedWarning, warning.message);
EXPECT_FALSE(OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
}
TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionNotOnWhitelist) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, false, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_EQ(1U, extension->install_warnings().size());
const extensions::InstallWarning& warning =
extension->install_warnings()[0];
EXPECT_EQ(kAutoApproveNotAllowedWarning, warning.message);
EXPECT_FALSE(OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
}
TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionNotOnWhitelist) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_INVALID, false, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_EQ(1U, extension->install_warnings().size());
const extensions::InstallWarning& warning =
extension->install_warnings()[0];
EXPECT_EQ(kAutoApproveNotAllowedWarning, warning.message);
EXPECT_FALSE(OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
}
TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionOnWhitelist) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_TRUE(extension->install_warnings().empty());
EXPECT_FALSE(OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
}
TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionOnWhitelist) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_FALSE, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_TRUE(extension->install_warnings().empty());
ASSERT_TRUE(OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
EXPECT_FALSE(*OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
}
TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionOnWhitelist) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_TRUE(extension->install_warnings().empty());
EXPECT_TRUE(OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
EXPECT_TRUE(*OAuth2ManifestHandler::GetOAuth2Info(*extension).auto_approve);
}
TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionOnWhitelist) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_INVALID, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
scoped_refptr<extensions::Extension> extension =
LoadExtension(manifest, &error);
EXPECT_EQ(
"Error at key 'oauth2.auto_approve'. Type is invalid. Expected boolean, "
"found string.",
error);
}
TEST_F(OAuth2ManifestTest, InvalidClientId) {
{
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_NOT_SET);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
LoadAndExpectError(manifest, errors::kInvalidOAuth2ClientId);
}
{
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_EMPTY);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
LoadAndExpectError(manifest, errors::kInvalidOAuth2ClientId);
}
}
TEST_F(OAuth2ManifestTest, ComponentInvalidClientId) {
// Component Apps without auto_approve must include a client ID.
{
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_NOT_SET);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
LoadAndExpectError(manifest, errors::kInvalidOAuth2ClientId,
ManifestLocation::kComponent);
}
{
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_EMPTY);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
LoadAndExpectError(manifest, errors::kInvalidOAuth2ClientId,
ManifestLocation::kComponent);
}
}
TEST_F(OAuth2ManifestTest, ComponentWithChromeClientId) {
{
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_NOT_SET);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest, ManifestLocation::kComponent);
EXPECT_FALSE(OAuth2ManifestHandler::GetOAuth2Info(*extension).client_id);
}
{
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_EMPTY);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest, ManifestLocation::kComponent);
ASSERT_TRUE(OAuth2ManifestHandler::GetOAuth2Info(*extension).client_id);
EXPECT_TRUE(
OAuth2ManifestHandler::GetOAuth2Info(*extension).client_id->empty());
}
}
TEST_F(OAuth2ManifestTest, ComponentWithStandardClientId) {
base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest, ManifestLocation::kComponent);
ASSERT_TRUE(OAuth2ManifestHandler::GetOAuth2Info(*extension).client_id);
EXPECT_EQ("client1",
*OAuth2ManifestHandler::GetOAuth2Info(*extension).client_id);
}
} // namespace extensions