summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfgorski@chromium.org <fgorski@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-17 23:47:44 +0000
committerfgorski@chromium.org <fgorski@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-17 23:47:44 +0000
commit79f177fcdb628ad2b44e0f788ad60e5e344d5834 (patch)
tree52d8cd2c9922f18c0659f42256cb7db2e7e0c727
parent07ccfc56c2ada34fcbd66e3ddfe294258e0b2f92 (diff)
downloadchromium_src-79f177fcdb628ad2b44e0f788ad60e5e344d5834.zip
chromium_src-79f177fcdb628ad2b44e0f788ad60e5e344d5834.tar.gz
chromium_src-79f177fcdb628ad2b44e0f788ad60e5e344d5834.tar.bz2
* Force token minting based on the oauth2.auto_approve setting
* Verify that the oauth2.auto_approve flag is allowed to be set in the manifest (based on whitelisting) BUG=155963 Review URL: https://chromiumcodereview.appspot.com/16638006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@206835 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/api/identity/identity_api.cc8
-rw-r--r--chrome/common/extensions/api/_manifest_features.json9
-rw-r--r--chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc191
-rw-r--r--chrome/common/extensions/api/identity/oauth2_manifest_handler.cc10
-rw-r--r--chrome/common/extensions/extension_manifest_constants.cc2
-rw-r--r--chrome/common/extensions/extension_manifest_constants.h1
6 files changed, 170 insertions, 51 deletions
diff --git a/chrome/browser/extensions/api/identity/identity_api.cc b/chrome/browser/extensions/api/identity/identity_api.cc
index 1f385fe..cdcd4dc 100644
--- a/chrome/browser/extensions/api/identity/identity_api.cc
+++ b/chrome/browser/extensions/api/identity/identity_api.cc
@@ -211,7 +211,13 @@ void IdentityGetAuthTokenFunction::StartMintToken(
return;
}
#endif
- StartGaiaRequest(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
+ if (oauth2_info.auto_approve)
+ // oauth2_info.auto_approve is protected by a whitelist in
+ // _manifest_features.json hence only selected extensions take
+ // advantage of forcefully minting the token.
+ StartGaiaRequest(OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE);
+ else
+ StartGaiaRequest(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
break;
case IdentityTokenCacheValue::CACHE_STATUS_TOKEN:
diff --git a/chrome/common/extensions/api/_manifest_features.json b/chrome/common/extensions/api/_manifest_features.json
index 4512c56..c3a168d 100644
--- a/chrome/common/extensions/api/_manifest_features.json
+++ b/chrome/common/extensions/api/_manifest_features.json
@@ -239,6 +239,15 @@
"extension", "packaged_app", "platform_app"
]
},
+ "oauth2.auto_approve": {
+ "channel": "stable",
+ "extension_types": [
+ "extension", "platform_app"
+ ],
+ "whitelist": [
+ "mdbihdcgjmagbcapkhhkjbbdlkflmbfo" // Placeholder to activate whitelist.
+ ]
+ },
"offline_enabled": {
"channel": "stable",
"extension_types": [
diff --git a/chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc b/chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc
index 2d56650..82f719a 100644
--- a/chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc
+++ b/chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc
@@ -10,9 +10,64 @@
namespace keys = extension_manifest_keys;
+namespace {
+
+// 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.";
+
+} // namespace
+
namespace extensions {
class OAuth2ManifestTest : public ExtensionManifestTest {
+ protected:
+ enum AutoApproveValue {
+ AUTO_APPROVE_NOT_SET,
+ AUTO_APPROVE_FALSE,
+ AUTO_APPROVE_TRUE,
+ AUTO_APPROVE_INVALID
+ };
+
+ base::DictionaryValue* CreateManifest(
+ AutoApproveValue auto_approve,
+ bool extension_id_whitelisted) {
+ parsed_manifest_.reset(base::test::ParseJson(
+ "{ \n"
+ " \"name\": \"test\", \n"
+ " \"version\": \"0.1\", \n"
+ " \"manifest_version\": 2, \n"
+ " \"oauth2\": { \n"
+ " \"client_id\": \"client1\", \n"
+ " \"scopes\": [ \"scope1\" ], \n"
+ " }, \n"
+ "} \n").release());
+ base::DictionaryValue* ext_manifest;
+ EXPECT_TRUE(parsed_manifest_->GetAsDictionary(&ext_manifest));
+ switch (auto_approve) {
+ case AUTO_APPROVE_NOT_SET:
+ break;
+ case AUTO_APPROVE_FALSE:
+ ext_manifest->SetBoolean(keys::kOAuth2AutoApprove, false);
+ break;
+ case AUTO_APPROVE_TRUE:
+ ext_manifest->SetBoolean(keys::kOAuth2AutoApprove, true);
+ break;
+ case AUTO_APPROVE_INVALID:
+ ext_manifest->SetString(keys::kOAuth2AutoApprove, "incorrect value");
+ break;
+ }
+ if (extension_id_whitelisted)
+ ext_manifest->SetString(keys::kKey, kExtensionKey);
+ return ext_manifest;
+ }
+
+ private:
+ scoped_ptr<Value> parsed_manifest_;
};
TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
@@ -26,7 +81,6 @@ TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
scopes->Append(new base::StringValue("scope1"));
scopes->Append(new base::StringValue("scope2"));
base_manifest.Set(keys::kOAuth2Scopes, scopes);
- base_manifest.SetBoolean(keys::kOAuth2AutoApprove, true);
// OAuth2 section should be parsed for an extension.
{
@@ -34,6 +88,8 @@ TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
// Lack of "app" section representa an extension. So the base manifest
// itself represents an extension.
ext_manifest.MergeDictionary(&base_manifest);
+ ext_manifest.SetString(keys::kKey, kExtensionKey);
+ ext_manifest.SetBoolean(keys::kOAuth2AutoApprove, true);
Manifest manifest(&ext_manifest, "test");
scoped_refptr<extensions::Extension> extension =
@@ -60,7 +116,7 @@ TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
EXPECT_EQ(2U, OAuth2Info::GetOAuth2Info(extension.get()).scopes.size());
EXPECT_EQ("scope1", OAuth2Info::GetOAuth2Info(extension.get()).scopes[0]);
EXPECT_EQ("scope2", OAuth2Info::GetOAuth2Info(extension.get()).scopes[1]);
- EXPECT_TRUE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
+ EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
}
// OAuth2 section should NOT be parsed for a hosted app.
@@ -84,58 +140,95 @@ TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
}
}
-TEST_F(OAuth2ManifestTest, OAuth2AutoApprove) {
- base::DictionaryValue* base_manifest;
- scoped_ptr<Value> parsed_manifest = base::test::ParseJson(
- "{ \n"
- " \"name\": \"test\", \n"
- " \"version\": \"0.1\", \n"
- " \"manifest_version\": 2, \n"
- " \"oauth2\": { \n"
- " \"client_id\": \"client1\", \n"
- " \"scopes\": [ \"scope1\" ], \n"
- " }, \n"
- "} \n");
-
- EXPECT_TRUE(parsed_manifest->GetAsDictionary(&base_manifest));
-
- // OAuth2 section without auto_approve should end up defaulting to false.
- {
- base::DictionaryValue ext_manifest;
- ext_manifest.MergeDictionary(base_manifest);
+TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionNotOnWhitelist) {
+ base::DictionaryValue* ext_manifest =
+ CreateManifest(AUTO_APPROVE_NOT_SET, false);
+ Manifest manifest(ext_manifest, "test");
+ scoped_refptr<extensions::Extension> extension =
+ LoadAndExpectSuccess(manifest);
+ EXPECT_TRUE(extension->install_warnings().empty());
+ EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
+}
- Manifest manifest(&ext_manifest, "test");
- scoped_refptr<extensions::Extension> extension =
- LoadAndExpectSuccess(manifest);
- EXPECT_TRUE(extension->install_warnings().empty());
- EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
- }
+TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionNotOnWhitelist) {
+ base::DictionaryValue* ext_manifest =
+ CreateManifest(AUTO_APPROVE_FALSE, false);
+ Manifest manifest(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(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
+}
- {
- base::DictionaryValue ext_manifest;
- ext_manifest.MergeDictionary(base_manifest);
- // OAuth2 section with auto_approve = false.
- ext_manifest.SetBoolean(keys::kOAuth2AutoApprove, false);
+TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionNotOnWhitelist) {
+ base::DictionaryValue* ext_manifest =
+ CreateManifest(AUTO_APPROVE_TRUE, false);
+ Manifest manifest(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(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
+}
- Manifest manifest(&ext_manifest, "test");
- scoped_refptr<extensions::Extension> extension =
- LoadAndExpectSuccess(manifest);
- EXPECT_TRUE(extension->install_warnings().empty());
- EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
- }
+TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionNotOnWhitelist) {
+ base::DictionaryValue* ext_manifest =
+ CreateManifest(AUTO_APPROVE_INVALID, false);
+ Manifest manifest(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(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
+}
- {
- base::DictionaryValue ext_manifest;
- ext_manifest.MergeDictionary(base_manifest);
- // OAuth2 section with auto_approve = true.
- ext_manifest.SetBoolean(keys::kOAuth2AutoApprove, true);
+TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionOnWhitelist) {
+ base::DictionaryValue* ext_manifest =
+ CreateManifest(AUTO_APPROVE_NOT_SET, true);
+ Manifest manifest(ext_manifest, "test");
+ scoped_refptr<extensions::Extension> extension =
+ LoadAndExpectSuccess(manifest);
+ EXPECT_TRUE(extension->install_warnings().empty());
+ EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
+}
- Manifest manifest(&ext_manifest, "test");
- scoped_refptr<extensions::Extension> extension =
- LoadAndExpectSuccess(manifest);
- EXPECT_TRUE(extension->install_warnings().empty());
- EXPECT_TRUE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
- }
+TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionOnWhitelist) {
+ base::DictionaryValue* ext_manifest =
+ CreateManifest(AUTO_APPROVE_FALSE, true);
+ Manifest manifest(ext_manifest, "test");
+ scoped_refptr<extensions::Extension> extension =
+ LoadAndExpectSuccess(manifest);
+ EXPECT_TRUE(extension->install_warnings().empty());
+ EXPECT_FALSE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
+}
+
+TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionOnWhitelist) {
+ base::DictionaryValue* ext_manifest =
+ CreateManifest(AUTO_APPROVE_TRUE, true);
+ Manifest manifest(ext_manifest, "test");
+ scoped_refptr<extensions::Extension> extension =
+ LoadAndExpectSuccess(manifest);
+ EXPECT_TRUE(extension->install_warnings().empty());
+ EXPECT_TRUE(OAuth2Info::GetOAuth2Info(extension.get()).auto_approve);
+}
+
+TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionOnWhitelist) {
+ base::DictionaryValue* ext_manifest =
+ CreateManifest(AUTO_APPROVE_INVALID, true);
+ Manifest manifest(ext_manifest, "test");
+ std::string error;
+ scoped_refptr<extensions::Extension> extension =
+ LoadExtension(manifest, &error);
+ EXPECT_EQ(
+ "Invalid value for 'oauth2.auto_approve'. Value must be true or false.",
+ error);
}
} // namespace extensions
diff --git a/chrome/common/extensions/api/identity/oauth2_manifest_handler.cc b/chrome/common/extensions/api/identity/oauth2_manifest_handler.cc
index a92a86f..dc97082 100644
--- a/chrome/common/extensions/api/identity/oauth2_manifest_handler.cc
+++ b/chrome/common/extensions/api/identity/oauth2_manifest_handler.cc
@@ -70,7 +70,15 @@ bool OAuth2ManifestHandler::Parse(Extension* extension,
info->scopes.push_back(scope);
}
- dict->GetBoolean(kAutoApprove, &info->auto_approve);
+ // HasPath checks for whether the manifest is allowed to have
+ // oauth2.auto_approve based on whitelist, and if it is present.
+ // GetBoolean reads the value of auto_approve directly from dict to prevent
+ // duplicate checking.
+ if (extension->manifest()->HasPath(keys::kOAuth2AutoApprove) &&
+ !dict->GetBoolean(kAutoApprove, &info->auto_approve)) {
+ *error = ASCIIToUTF16(errors::kInvalidOAuth2AutoApprove);
+ return false;
+ }
extension->SetManifestData(keys::kOAuth2, info.release());
return true;
diff --git a/chrome/common/extensions/extension_manifest_constants.cc b/chrome/common/extensions/extension_manifest_constants.cc
index 1ea6a83..8f2e546 100644
--- a/chrome/common/extensions/extension_manifest_constants.cc
+++ b/chrome/common/extensions/extension_manifest_constants.cc
@@ -438,6 +438,8 @@ const char kInvalidNaClModulesPath[] =
"Invalid value for 'nacl_modules[*].path'.";
const char kInvalidNaClModulesMIMEType[] =
"Invalid value for 'nacl_modules[*].mime_type'.";
+const char kInvalidOAuth2AutoApprove[] =
+ "Invalid value for 'oauth2.auto_approve'. Value must be true or false.";
const char kInvalidOAuth2ClientId[] =
"Invalid value for 'oauth2.client_id'.";
const char kInvalidOAuth2Scopes[] =
diff --git a/chrome/common/extensions/extension_manifest_constants.h b/chrome/common/extensions/extension_manifest_constants.h
index 601b944..d597dc0 100644
--- a/chrome/common/extensions/extension_manifest_constants.h
+++ b/chrome/common/extensions/extension_manifest_constants.h
@@ -323,6 +323,7 @@ namespace extension_manifest_errors {
extern const char kInvalidNaClModulesMIMEType[];
extern const char kInvalidNaClModulesPath[];
extern const char kInvalidName[];
+ extern const char kInvalidOAuth2AutoApprove[];
extern const char kInvalidOAuth2ClientId[];
extern const char kInvalidOAuth2Scopes[];
extern const char kInvalidOfflineEnabled[];