Index: chrome/browser/extensions/api/identity/identity_apitest.cc |
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc |
index 9bf130d64a4e7858b8a6ea2d68f6b25545fc91c3..0b04145ad3335ebf92d59ab6815254eac72ebccf 100644 |
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc |
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc |
@@ -19,6 +19,7 @@ |
#include "content/public/browser/notification_service.h" |
#include "content/public/browser/notification_source.h" |
#include "content/public/test/test_utils.h" |
+#include "extensions/common/id_util.h" |
#include "google_apis/gaia/google_service_auth_error.h" |
#include "google_apis/gaia/oauth2_mint_token_flow.h" |
#include "googleurl/src/gurl.h" |
@@ -37,6 +38,7 @@ namespace errors = identity_constants; |
namespace utils = extension_function_test_utils; |
static const char kAccessToken[] = "auth_token"; |
+static const char kExtensionId[] = "ext_id"; |
// This helps us be able to wait until an AsyncExtensionFunction calls |
// SendResponse. |
@@ -158,7 +160,7 @@ class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow { |
break; |
} |
case MINT_TOKEN_SUCCESS: { |
- delegate_->OnMintTokenSuccess(kAccessToken); |
+ delegate_->OnMintTokenSuccess(kAccessToken, 3600); |
break; |
} |
case MINT_TOKEN_FAILURE: { |
@@ -273,9 +275,9 @@ class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest { |
return ext; |
} |
- void InitializeTestAPIFactory() { |
- IdentityAPI::GetFactoryInstance()->SetTestingFactory( |
- browser()->profile(), &IdentityAPITestFactory); |
+ IdentityAPI* id_api() { |
+ return IdentityAPI::GetFactoryInstance()->GetForProfile( |
+ browser()->profile()); |
} |
}; |
@@ -330,6 +332,28 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
} |
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
+ NonInteractiveMintAdviceSuccess) { |
+ scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
+ func->set_extension(extension); |
+ EXPECT_CALL(*func.get(), HasLoginToken()) |
+ .WillOnce(Return(true)); |
+ TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( |
+ TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); |
+ EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); |
+ std::string error = utils::RunFunctionAndReturnError( |
+ func.get(), "[{}]", browser()); |
+ EXPECT_TRUE(StartsWithASCII(error, errors::kNoGrant, false)); |
+ EXPECT_FALSE(func->login_ui_shown()); |
+ EXPECT_FALSE(func->install_ui_shown()); |
+ |
+ const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); |
+ EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE, |
+ id_api()->GetCachedToken(extension->id(), |
+ oauth2_info.scopes).status()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
NonInteractiveMintBadCredentials) { |
scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
@@ -348,7 +372,9 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
NonInteractiveSuccess) { |
scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
- func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ func->set_extension(extension); |
+ const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); |
EXPECT_CALL(*func.get(), HasLoginToken()) |
.WillOnce(Return(true)); |
TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( |
@@ -361,6 +387,9 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
EXPECT_EQ(std::string(kAccessToken), access_token); |
EXPECT_FALSE(func->login_ui_shown()); |
EXPECT_FALSE(func->install_ui_shown()); |
+ EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, |
+ id_api()->GetCachedToken(extension->id(), |
+ oauth2_info.scopes).status()); |
} |
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
@@ -486,7 +515,9 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
InteractiveLoginSuccessApprovalDoneMintSuccess) { |
scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
- func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ func->set_extension(extension); |
+ const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); |
EXPECT_CALL(*func.get(), HasLoginToken()) |
.WillOnce(Return(false)); |
func->set_login_ui_result(true); |
@@ -506,6 +537,9 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
EXPECT_EQ(std::string(kAccessToken), access_token); |
EXPECT_TRUE(func->login_ui_shown()); |
EXPECT_TRUE(func->install_ui_shown()); |
+ EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, |
+ id_api()->GetCachedToken(extension->id(), |
+ oauth2_info.scopes).status()); |
} |
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
@@ -572,7 +606,6 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
} |
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) { |
- InitializeTestAPIFactory(); |
scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
func->set_extension(extension); |
@@ -615,7 +648,6 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) { |
} |
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) { |
- InitializeTestAPIFactory(); |
scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
func->set_extension(extension); |
@@ -665,7 +697,6 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) { |
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
InteractiveQueuedNoninteractiveFails) { |
- InitializeTestAPIFactory(); |
scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
func->set_extension(extension); |
@@ -697,6 +728,196 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
queue->RequestComplete(type, extension->id(), scopes, &queued_request); |
} |
+IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
+ NonInteractiveCacheHit) { |
+ scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
+ func->set_extension(extension); |
+ |
+ // pre-populate the cache with a token |
+ const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); |
+ IdentityTokenCacheValue token(kAccessToken, |
+ base::TimeDelta::FromSeconds(3600)); |
+ id_api()->SetCachedToken(extension->id(), oauth2_info.scopes, token); |
+ |
+ // Get a token. Should not require a GAIA request. |
+ EXPECT_CALL(*func.get(), HasLoginToken()) |
+ .WillOnce(Return(true)); |
+ scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( |
+ func.get(), "[{}]", browser())); |
+ std::string access_token; |
+ EXPECT_TRUE(value->GetAsString(&access_token)); |
+ EXPECT_EQ(std::string(kAccessToken), access_token); |
+ EXPECT_FALSE(func->login_ui_shown()); |
+ EXPECT_FALSE(func->install_ui_shown()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
+ NonInteractiveIssueAdviceCacheHit) { |
+ scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
+ func->set_extension(extension); |
+ |
+ // pre-populate the cache with advice |
+ const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); |
+ IssueAdviceInfo info; |
+ IdentityTokenCacheValue token(info); |
+ id_api()->SetCachedToken(extension->id(), oauth2_info.scopes, token); |
+ |
+ // Should return an error without a GAIA request. |
+ EXPECT_CALL(*func.get(), HasLoginToken()) |
+ .WillOnce(Return(true)); |
+ std::string error = utils::RunFunctionAndReturnError( |
+ func.get(), "[{}]", browser()); |
+ EXPECT_EQ(std::string(errors::kNoGrant), error); |
+ EXPECT_FALSE(func->login_ui_shown()); |
+ EXPECT_FALSE(func->install_ui_shown()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
+ InteractiveCacheHit) { |
+ scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
+ func->set_extension(extension); |
+ |
+ // Create a fake request to block the queue. |
+ const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); |
+ std::set<std::string> scopes(oauth2_info.scopes.begin(), |
+ oauth2_info.scopes.end()); |
+ IdentityMintRequestQueue* queue = id_api()->mint_queue(); |
+ MockQueuedMintRequest queued_request; |
+ IdentityMintRequestQueue::MintType type = |
+ IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE; |
+ |
+ EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); |
+ queue->RequestStart(type, extension->id(), scopes, &queued_request); |
+ |
+ // The real request will start processing, but wait in the queue behind |
+ // the blocker. |
+ EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true)); |
+ TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( |
+ TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); |
+ EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); |
+ RunFunctionAsync(func, "[{\"interactive\": true}]"); |
+ |
+ // Populate the cache with a token while the request is blocked. |
+ IdentityTokenCacheValue token(kAccessToken, |
+ base::TimeDelta::FromSeconds(3600)); |
+ id_api()->SetCachedToken(extension->id(), oauth2_info.scopes, token); |
+ |
+ // When we wake up the request, it returns the cached token without |
+ // displaying a UI, or hitting GAIA. |
+ |
+ queue->RequestComplete(type, extension->id(), scopes, &queued_request); |
+ |
+ scoped_ptr<base::Value> value(WaitForSingleResult(func)); |
+ std::string access_token; |
+ EXPECT_TRUE(value->GetAsString(&access_token)); |
+ EXPECT_EQ(std::string(kAccessToken), access_token); |
+ EXPECT_FALSE(func->login_ui_shown()); |
+ EXPECT_FALSE(func->install_ui_shown()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, |
+ LoginInvalidatesTokenCache) { |
+ scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); |
+ scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); |
+ func->set_extension(extension); |
+ |
+ // pre-populate the cache with a token |
+ const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); |
+ IdentityTokenCacheValue token(kAccessToken, |
+ base::TimeDelta::FromSeconds(3600)); |
+ id_api()->SetCachedToken(extension->id(), oauth2_info.scopes, token); |
+ |
+ // Because the user is not signed in, the token will be removed, |
+ // and we'll hit GAIA for new tokens. |
+ EXPECT_CALL(*func.get(), HasLoginToken()) |
+ .WillOnce(Return(false)); |
+ func->set_login_ui_result(true); |
+ TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow( |
+ TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); |
+ TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow( |
+ TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get()); |
+ EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)) |
+ .WillOnce(Return(flow1)) |
+ .WillOnce(Return(flow2)); |
+ |
+ func->set_install_ui_result(true); |
+ scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( |
+ func.get(), "[{\"interactive\": true}]", browser())); |
+ std::string access_token; |
+ EXPECT_TRUE(value->GetAsString(&access_token)); |
+ EXPECT_EQ(std::string(kAccessToken), access_token); |
+ EXPECT_TRUE(func->login_ui_shown()); |
+ EXPECT_TRUE(func->install_ui_shown()); |
+ EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, |
+ id_api()->GetCachedToken(extension->id(), |
+ oauth2_info.scopes).status()); |
+} |
+ |
+class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest { |
+ protected: |
+ bool InvalidateDefaultToken() { |
+ scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func( |
+ new IdentityRemoveCachedAuthTokenFunction); |
+ func->set_extension(utils::CreateEmptyExtension(kExtensionId)); |
+ return utils::RunFunction( |
+ func, std::string("[{\"token\": \"") + kAccessToken + "\"}]", browser(), |
+ extension_function_test_utils::NONE); |
+ } |
+ |
+ IdentityAPI* id_api() { |
+ return IdentityAPI::GetFactoryInstance()->GetForProfile( |
+ browser()->profile()); |
+ } |
+ |
+ void SetCachedToken(IdentityTokenCacheValue& token_data) { |
+ id_api()->SetCachedToken(extensions::id_util::GenerateId(kExtensionId), |
+ std::vector<std::string>(), token_data); |
+ } |
+ |
+ const IdentityTokenCacheValue& GetCachedToken() { |
+ return id_api()->GetCachedToken( |
+ extensions::id_util::GenerateId(kExtensionId), |
+ std::vector<std::string>()); |
+ } |
+}; |
+ |
+IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) { |
+ EXPECT_TRUE(InvalidateDefaultToken()); |
+ EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND, |
+ GetCachedToken().status()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) { |
+ IssueAdviceInfo info; |
+ IdentityTokenCacheValue advice(info); |
+ SetCachedToken(advice); |
+ EXPECT_TRUE(InvalidateDefaultToken()); |
+ EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE, |
+ GetCachedToken().status()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) { |
+ IdentityTokenCacheValue token("non_matching_token", |
+ base::TimeDelta::FromSeconds(3600)); |
+ SetCachedToken(token); |
+ EXPECT_TRUE(InvalidateDefaultToken()); |
+ EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, |
+ GetCachedToken().status()); |
+ EXPECT_EQ("non_matching_token", GetCachedToken().token()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) { |
+ IdentityTokenCacheValue token(kAccessToken, |
+ base::TimeDelta::FromSeconds(3600)); |
+ SetCachedToken(token); |
+ EXPECT_TRUE(InvalidateDefaultToken()); |
+ EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND, |
+ GetCachedToken().status()); |
+} |
+ |
class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest { |
protected: |
void RunAndCheckBounds( |