Home | History | Annotate | Download | only in supervised_user
      1 // Copyright 2014 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/bind.h"
      6 #include "base/memory/scoped_ptr.h"
      7 #include "base/strings/stringprintf.h"
      8 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
      9 #include "chrome/browser/supervised_user/supervised_user_refresh_token_fetcher.h"
     10 #include "chrome/test/base/testing_profile.h"
     11 #include "content/public/test/test_browser_thread_bundle.h"
     12 #include "google_apis/gaia/gaia_constants.h"
     13 #include "google_apis/gaia/gaia_oauth_client.h"
     14 #include "google_apis/gaia/gaia_urls.h"
     15 #include "google_apis/gaia/google_service_auth_error.h"
     16 #include "google_apis/gaia/oauth2_token_service.h"
     17 #include "net/base/net_errors.h"
     18 #include "net/base/url_util.h"
     19 #include "net/http/http_request_headers.h"
     20 #include "net/http/http_status_code.h"
     21 #include "net/url_request/test_url_fetcher_factory.h"
     22 #include "net/url_request/url_fetcher_delegate.h"
     23 #include "testing/gtest/include/gtest/gtest.h"
     24 
     25 namespace {
     26 
     27 const char kAccountId[] = "account_id";
     28 const char kDeviceName[] = "Compy";
     29 const char kSupervisedUserId[] = "abcdef";
     30 
     31 const char kAccessToken[] = "accesstoken";
     32 const char kAuthorizationCode[] = "authorizationcode";
     33 const char kSupervisedUserToken[] = "supervisedusertoken";
     34 const char kOAuth2RefreshToken[] = "refreshtoken";
     35 
     36 const char kIssueTokenResponseFormat[] =
     37     "{"
     38     "  \"code\": \"%s\""
     39     "}";
     40 
     41 const char kGetRefreshTokenResponseFormat[] =
     42     "{"
     43     "  \"access_token\": \"<ignored>\","
     44     "  \"expires_in\": 12345,"
     45     "  \"refresh_token\": \"%s\""
     46     "}";
     47 
     48 // Utility methods --------------------------------------------------
     49 
     50 // Slightly hacky way to extract a value from a URL-encoded POST request body.
     51 bool GetValueForKey(const std::string& encoded_string,
     52                     const std::string& key,
     53                     std::string* value) {
     54   GURL url("http://example.com/?" + encoded_string);
     55   return net::GetValueForKeyInQuery(url, key, value);
     56 }
     57 
     58 void SendResponse(net::TestURLFetcher* url_fetcher,
     59                   const std::string& response) {
     60   url_fetcher->set_status(
     61       net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0));
     62   url_fetcher->set_response_code(net::HTTP_OK);
     63   url_fetcher->SetResponseString(response);
     64   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
     65 }
     66 
     67 void SetNetworkError(net::TestURLFetcher* url_fetcher, int error) {
     68   url_fetcher->set_status(
     69       net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
     70   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
     71 }
     72 
     73 void SetHttpError(net::TestURLFetcher* url_fetcher, int error) {
     74   url_fetcher->set_status(net::URLRequestStatus());
     75   url_fetcher->set_response_code(error);
     76   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
     77 }
     78 
     79 void VerifyTokenRequest(
     80     std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests) {
     81   ASSERT_EQ(1u, requests.size());
     82   EXPECT_EQ(1u, requests[0].scopes.size());
     83   EXPECT_EQ(1u, requests[0].scopes.count(GaiaConstants::kOAuth1LoginScope));
     84 }
     85 
     86 }  // namespace
     87 
     88 class SupervisedUserRefreshTokenFetcherTest : public testing::Test {
     89  public:
     90   SupervisedUserRefreshTokenFetcherTest();
     91   virtual ~SupervisedUserRefreshTokenFetcherTest() {}
     92 
     93  protected:
     94   void StartFetching();
     95 
     96   net::TestURLFetcher* GetIssueTokenRequest();
     97   net::TestURLFetcher* GetRefreshTokenRequest();
     98 
     99   void MakeOAuth2TokenServiceRequestSucceed();
    100   void MakeOAuth2TokenServiceRequestFail(GoogleServiceAuthError::State error);
    101   void MakeIssueTokenRequestSucceed();
    102   void MakeRefreshTokenFetchSucceed();
    103 
    104   void Reset();
    105 
    106   const GoogleServiceAuthError& error() const { return error_; }
    107   const std::string& token() const { return token_; }
    108 
    109  private:
    110   void OnTokenFetched(const GoogleServiceAuthError& error,
    111                       const std::string& token);
    112 
    113   content::TestBrowserThreadBundle thread_bundle_;
    114   TestingProfile profile_;
    115   FakeProfileOAuth2TokenService oauth2_token_service_;
    116   net::TestURLFetcherFactory url_fetcher_factory_;
    117   scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher_;
    118 
    119   GoogleServiceAuthError error_;
    120   std::string token_;
    121   base::WeakPtrFactory<SupervisedUserRefreshTokenFetcherTest> weak_ptr_factory_;
    122 };
    123 
    124 SupervisedUserRefreshTokenFetcherTest::SupervisedUserRefreshTokenFetcherTest()
    125     : token_fetcher_(SupervisedUserRefreshTokenFetcher::Create(
    126                          &oauth2_token_service_,
    127                          kAccountId,
    128                          profile_.GetRequestContext())),
    129       error_(GoogleServiceAuthError::NONE),
    130       weak_ptr_factory_(this) {}
    131 
    132 void SupervisedUserRefreshTokenFetcherTest::StartFetching() {
    133   oauth2_token_service_.IssueRefreshToken(kOAuth2RefreshToken);
    134   token_fetcher_->Start(
    135       kSupervisedUserId,
    136       kDeviceName,
    137       base::Bind(
    138           &SupervisedUserRefreshTokenFetcherTest::OnTokenFetched,
    139           weak_ptr_factory_.GetWeakPtr()));
    140 }
    141 
    142 net::TestURLFetcher*
    143 SupervisedUserRefreshTokenFetcherTest::GetIssueTokenRequest() {
    144   net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(1);
    145   if (!url_fetcher)
    146     return NULL;
    147 
    148   EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_issue_token_url(),
    149             url_fetcher->GetOriginalURL());
    150   std::string access_token;
    151   net::HttpRequestHeaders headers;
    152   url_fetcher->GetExtraRequestHeaders(&headers);
    153   EXPECT_TRUE(headers.GetHeader("Authorization", &access_token));
    154   EXPECT_EQ(std::string("Bearer ") + kAccessToken, access_token);
    155   const std::string upload_data = url_fetcher->upload_data();
    156   std::string supervised_user_id;
    157   EXPECT_TRUE(GetValueForKey(upload_data, "profile_id", &supervised_user_id));
    158   EXPECT_EQ(kSupervisedUserId, supervised_user_id);
    159   std::string device_name;
    160   EXPECT_TRUE(GetValueForKey(upload_data, "device_name", &device_name));
    161   EXPECT_EQ(kDeviceName, device_name);
    162   return url_fetcher;
    163 }
    164 
    165 net::TestURLFetcher*
    166 SupervisedUserRefreshTokenFetcherTest::GetRefreshTokenRequest() {
    167   net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(
    168       gaia::GaiaOAuthClient::kUrlFetcherId);
    169   if (!url_fetcher)
    170     return NULL;
    171 
    172   EXPECT_EQ(GaiaUrls::GetInstance()->oauth2_token_url(),
    173             url_fetcher->GetOriginalURL());
    174   std::string auth_code;
    175   EXPECT_TRUE(GetValueForKey(url_fetcher->upload_data(), "code", &auth_code));
    176   EXPECT_EQ(kAuthorizationCode, auth_code);
    177   return url_fetcher;
    178 }
    179 
    180 void
    181 SupervisedUserRefreshTokenFetcherTest::MakeOAuth2TokenServiceRequestSucceed() {
    182   std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests =
    183       oauth2_token_service_.GetPendingRequests();
    184   VerifyTokenRequest(requests);
    185   base::Time expiration_date = base::Time::Now() +
    186                                base::TimeDelta::FromHours(1);
    187   oauth2_token_service_.IssueTokenForScope(requests[0].scopes,
    188                                            kAccessToken,
    189                                            expiration_date);
    190 }
    191 
    192 void
    193 SupervisedUserRefreshTokenFetcherTest::MakeOAuth2TokenServiceRequestFail(
    194     GoogleServiceAuthError::State error) {
    195   std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests =
    196       oauth2_token_service_.GetPendingRequests();
    197   VerifyTokenRequest(requests);
    198   oauth2_token_service_.IssueErrorForScope(requests[0].scopes,
    199                                            GoogleServiceAuthError(error));
    200 }
    201 
    202 void SupervisedUserRefreshTokenFetcherTest::MakeIssueTokenRequestSucceed() {
    203   SendResponse(GetIssueTokenRequest(),
    204                base::StringPrintf(kIssueTokenResponseFormat,
    205                                   kAuthorizationCode));
    206 }
    207 
    208 void SupervisedUserRefreshTokenFetcherTest::MakeRefreshTokenFetchSucceed() {
    209   SendResponse(GetRefreshTokenRequest(),
    210                base::StringPrintf(kGetRefreshTokenResponseFormat,
    211                                   kSupervisedUserToken));
    212 }
    213 
    214 void SupervisedUserRefreshTokenFetcherTest::Reset() {
    215   token_fetcher_.reset();
    216 }
    217 
    218 void SupervisedUserRefreshTokenFetcherTest::OnTokenFetched(
    219     const GoogleServiceAuthError& error,
    220     const std::string& token) {
    221   error_ = error;
    222   token_ = token;
    223 }
    224 
    225 // Tests --------------------------------------------------------
    226 
    227 TEST_F(SupervisedUserRefreshTokenFetcherTest, Success) {
    228   StartFetching();
    229   MakeOAuth2TokenServiceRequestSucceed();
    230   MakeIssueTokenRequestSucceed();
    231   MakeRefreshTokenFetchSucceed();
    232 
    233   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
    234   EXPECT_EQ(kSupervisedUserToken, token());
    235 }
    236 
    237 TEST_F(SupervisedUserRefreshTokenFetcherTest, ExpiredAccessToken) {
    238   StartFetching();
    239   MakeOAuth2TokenServiceRequestSucceed();
    240   SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
    241   MakeOAuth2TokenServiceRequestSucceed();
    242   MakeIssueTokenRequestSucceed();
    243   MakeRefreshTokenFetchSucceed();
    244 
    245   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
    246   EXPECT_EQ(kSupervisedUserToken, token());
    247 }
    248 
    249 TEST_F(SupervisedUserRefreshTokenFetcherTest, ExpiredAccessTokenRetry) {
    250   // If we get a 401 error for the second time, we should give up instead of
    251   // retrying again.
    252   StartFetching();
    253   MakeOAuth2TokenServiceRequestSucceed();
    254   SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
    255   MakeOAuth2TokenServiceRequestSucceed();
    256   SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
    257 
    258   EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
    259   EXPECT_EQ(net::ERR_FAILED, error().network_error());
    260   EXPECT_EQ(std::string(), token());
    261 }
    262 
    263 TEST_F(SupervisedUserRefreshTokenFetcherTest, MalformedIssueTokenResponse) {
    264   StartFetching();
    265   MakeOAuth2TokenServiceRequestSucceed();
    266   SendResponse(GetIssueTokenRequest(), "choke");
    267 
    268   EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
    269   EXPECT_EQ(net::ERR_INVALID_RESPONSE, error().network_error());
    270   EXPECT_EQ(std::string(), token());
    271 }
    272 
    273 TEST_F(SupervisedUserRefreshTokenFetcherTest, FetchAccessTokenFailure) {
    274   StartFetching();
    275   MakeOAuth2TokenServiceRequestFail(
    276       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
    277 
    278   EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, error().state());
    279   EXPECT_EQ(std::string(), token());
    280 }
    281 
    282 TEST_F(SupervisedUserRefreshTokenFetcherTest, IssueTokenNetworkError) {
    283   StartFetching();
    284   MakeOAuth2TokenServiceRequestSucceed();
    285   SetNetworkError(GetIssueTokenRequest(), net::ERR_SSL_PROTOCOL_ERROR);
    286 
    287   EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
    288   EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, error().network_error());
    289   EXPECT_EQ(std::string(), token());
    290 }
    291 
    292 TEST_F(SupervisedUserRefreshTokenFetcherTest, FetchRefreshTokenNetworkError) {
    293   StartFetching();
    294   MakeOAuth2TokenServiceRequestSucceed();
    295   MakeIssueTokenRequestSucceed();
    296   SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
    297   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
    298   SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
    299 
    300   EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
    301   EXPECT_EQ(net::ERR_FAILED, error().network_error());
    302   EXPECT_EQ(std::string(), token());
    303 }
    304 
    305 TEST_F(SupervisedUserRefreshTokenFetcherTest,
    306        FetchRefreshTokenTransientNetworkError) {
    307   StartFetching();
    308   MakeOAuth2TokenServiceRequestSucceed();
    309   MakeIssueTokenRequestSucceed();
    310   SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
    311 
    312   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
    313   MakeRefreshTokenFetchSucceed();
    314 
    315   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
    316   EXPECT_EQ(kSupervisedUserToken, token());
    317 }
    318 
    319 TEST_F(SupervisedUserRefreshTokenFetcherTest, FetchRefreshTokenBadRequest) {
    320   StartFetching();
    321   MakeOAuth2TokenServiceRequestSucceed();
    322   MakeIssueTokenRequestSucceed();
    323   SetHttpError(GetRefreshTokenRequest(), net::HTTP_BAD_REQUEST);
    324 
    325   EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
    326   EXPECT_EQ(net::ERR_FAILED, error().network_error());
    327   EXPECT_EQ(std::string(), token());
    328 }
    329 
    330 TEST_F(SupervisedUserRefreshTokenFetcherTest, CancelWhileFetchingAccessToken) {
    331   StartFetching();
    332   Reset();
    333 
    334   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
    335   EXPECT_EQ(std::string(), token());
    336 }
    337 
    338 TEST_F(SupervisedUserRefreshTokenFetcherTest, CancelWhileCallingIssueToken) {
    339   StartFetching();
    340   MakeOAuth2TokenServiceRequestSucceed();
    341   Reset();
    342 
    343   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
    344   EXPECT_EQ(std::string(), token());
    345 }
    346 
    347 TEST_F(SupervisedUserRefreshTokenFetcherTest, CancelWhileFetchingRefreshToken) {
    348   StartFetching();
    349   MakeOAuth2TokenServiceRequestSucceed();
    350   MakeIssueTokenRequestSucceed();
    351   Reset();
    352 
    353   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
    354   EXPECT_EQ(std::string(), token());
    355 }
    356