Home | History | Annotate | Download | only in identity
      1 // Copyright (c) 2013 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 "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/run_loop.h"
     11 #include "content/public/test/test_browser_thread.h"
     12 #include "testing/gmock/include/gmock/gmock.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 namespace extensions {
     16 
     17 class FakeWebAuthFlow : public WebAuthFlow {
     18  public:
     19   explicit FakeWebAuthFlow(WebAuthFlow::Delegate* delegate)
     20       : WebAuthFlow(delegate,
     21                     NULL,
     22                     GURL(),
     23                     WebAuthFlow::INTERACTIVE) {}
     24 
     25   virtual void Start() OVERRIDE {}
     26 };
     27 
     28 class TestGaiaWebAuthFlow : public GaiaWebAuthFlow {
     29  public:
     30   TestGaiaWebAuthFlow(GaiaWebAuthFlow::Delegate* delegate,
     31                       const ExtensionTokenKey* token_key,
     32                       const std::string oauth2_client_id,
     33                       GoogleServiceAuthError::State ubertoken_error_state)
     34       : GaiaWebAuthFlow(delegate, NULL, token_key, oauth2_client_id, "en-us"),
     35         ubertoken_error_(ubertoken_error_state) {}
     36 
     37   virtual void Start() OVERRIDE {
     38     if (ubertoken_error_.state() == GoogleServiceAuthError::NONE)
     39       OnUbertokenSuccess("fake_ubertoken");
     40     else
     41       OnUbertokenFailure(ubertoken_error_);
     42   }
     43 
     44  private:
     45   virtual scoped_ptr<WebAuthFlow> CreateWebAuthFlow(GURL url) OVERRIDE {
     46     return scoped_ptr<WebAuthFlow>(new FakeWebAuthFlow(this));
     47   }
     48 
     49   GoogleServiceAuthError ubertoken_error_;
     50 };
     51 
     52 class MockGaiaWebAuthFlowDelegate : public GaiaWebAuthFlow::Delegate {
     53  public:
     54   MOCK_METHOD3(OnGaiaFlowFailure,
     55                void(GaiaWebAuthFlow::Failure failure,
     56                     GoogleServiceAuthError service_error,
     57                     const std::string& oauth_error));
     58   MOCK_METHOD2(OnGaiaFlowCompleted,
     59                void(const std::string& access_token,
     60                     const std::string& expiration));
     61 };
     62 
     63 class IdentityGaiaWebAuthFlowTest : public testing::Test {
     64  public:
     65   IdentityGaiaWebAuthFlowTest()
     66       : ubertoken_error_state_(GoogleServiceAuthError::NONE),
     67         fake_ui_thread_(content::BrowserThread::UI, &message_loop_) {}
     68 
     69   virtual void TearDown() {
     70     testing::Test::TearDown();
     71     base::RunLoop loop;
     72     loop.RunUntilIdle();  // Run tasks so FakeWebAuthFlows get deleted.
     73   }
     74 
     75   scoped_ptr<TestGaiaWebAuthFlow> CreateTestFlow() {
     76     ExtensionTokenKey token_key(
     77         "extension_id", "account_id", std::set<std::string>());
     78     return scoped_ptr<TestGaiaWebAuthFlow>(new TestGaiaWebAuthFlow(
     79         &delegate_, &token_key, "fake.client.id", ubertoken_error_state_));
     80   }
     81 
     82   std::string GetFinalTitle(const std::string& fragment) {
     83     return std::string("Loading id.client.fake:/extension_id#") + fragment;
     84   }
     85 
     86   GoogleServiceAuthError GetNoneServiceError() {
     87     return GoogleServiceAuthError(GoogleServiceAuthError::NONE);
     88   }
     89 
     90   void set_ubertoken_error(
     91       GoogleServiceAuthError::State ubertoken_error_state) {
     92     ubertoken_error_state_ = ubertoken_error_state;
     93   }
     94 
     95  protected:
     96   testing::StrictMock<MockGaiaWebAuthFlowDelegate> delegate_;
     97   GoogleServiceAuthError::State ubertoken_error_state_;
     98   base::MessageLoop message_loop_;
     99   content::TestBrowserThread fake_ui_thread_;
    100 };
    101 
    102 TEST_F(IdentityGaiaWebAuthFlowTest, OAuthError) {
    103   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    104   flow->Start();
    105   EXPECT_CALL(delegate_, OnGaiaFlowFailure(
    106           GaiaWebAuthFlow::OAUTH_ERROR,
    107           GoogleServiceAuthError(GoogleServiceAuthError::NONE),
    108           "access_denied"));
    109   flow->OnAuthFlowTitleChange(GetFinalTitle("error=access_denied"));
    110 }
    111 
    112 TEST_F(IdentityGaiaWebAuthFlowTest, Token) {
    113   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    114   flow->Start();
    115   EXPECT_CALL(delegate_, OnGaiaFlowCompleted("fake_access_token", ""));
    116   flow->OnAuthFlowTitleChange(GetFinalTitle("access_token=fake_access_token"));
    117 }
    118 
    119 TEST_F(IdentityGaiaWebAuthFlowTest, TokenAndExpiration) {
    120   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    121   flow->Start();
    122   EXPECT_CALL(delegate_, OnGaiaFlowCompleted("fake_access_token", "3600"));
    123   flow->OnAuthFlowTitleChange(
    124       GetFinalTitle("access_token=fake_access_token&expires_in=3600"));
    125 }
    126 
    127 TEST_F(IdentityGaiaWebAuthFlowTest, ExtraFragmentParametersSuccess) {
    128   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    129   flow->Start();
    130   EXPECT_CALL(delegate_,
    131               OnGaiaFlowCompleted("fake_access_token", "3600"));
    132   flow->OnAuthFlowTitleChange(GetFinalTitle("chaff1=stuff&"
    133                                             "expires_in=3600&"
    134                                             "chaff2=and&"
    135                                             "nonerror=fake_error&"
    136                                             "chaff3=nonsense&"
    137                                             "access_token=fake_access_token&"
    138                                             "chaff4="));
    139 }
    140 
    141 TEST_F(IdentityGaiaWebAuthFlowTest, ExtraFragmentParametersError) {
    142   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    143   flow->Start();
    144   EXPECT_CALL(delegate_, OnGaiaFlowFailure(
    145           GaiaWebAuthFlow::OAUTH_ERROR,
    146           GoogleServiceAuthError(GoogleServiceAuthError::NONE),
    147           "fake_error"));
    148   flow->OnAuthFlowTitleChange(GetFinalTitle("chaff1=stuff&"
    149                                             "expires_in=3600&"
    150                                             "chaff2=and&"
    151                                             "error=fake_error&"
    152                                             "chaff3=nonsense&"
    153                                             "access_token=fake_access_token&"
    154                                             "chaff4="));
    155 }
    156 
    157 TEST_F(IdentityGaiaWebAuthFlowTest, TitleSpam) {
    158   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    159   flow->Start();
    160   flow->OnAuthFlowTitleChange(
    161       "Loading https://extension_id.chromiumapp.org/#error=non_final_title");
    162   flow->OnAuthFlowTitleChange("I'm feeling entitled.");
    163   flow->OnAuthFlowTitleChange("");
    164   flow->OnAuthFlowTitleChange(
    165       "Loading id.client.fake:/bad_extension_id#error=non_final_title");
    166   flow->OnAuthFlowTitleChange(
    167       "Loading bad.id.client.fake:/extension_id#error=non_final_title");
    168   EXPECT_CALL(delegate_, OnGaiaFlowCompleted("fake_access_token", ""));
    169   flow->OnAuthFlowTitleChange(GetFinalTitle("access_token=fake_access_token"));
    170 }
    171 
    172 TEST_F(IdentityGaiaWebAuthFlowTest, EmptyFragment) {
    173   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    174   flow->Start();
    175   EXPECT_CALL(
    176       delegate_,
    177       OnGaiaFlowFailure(
    178           GaiaWebAuthFlow::INVALID_REDIRECT,
    179           GoogleServiceAuthError(GoogleServiceAuthError::NONE),
    180           ""));
    181   flow->OnAuthFlowTitleChange(GetFinalTitle(""));
    182 }
    183 
    184 TEST_F(IdentityGaiaWebAuthFlowTest, JunkFragment) {
    185   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    186   flow->Start();
    187   EXPECT_CALL(
    188       delegate_,
    189       OnGaiaFlowFailure(
    190           GaiaWebAuthFlow::INVALID_REDIRECT,
    191           GoogleServiceAuthError(GoogleServiceAuthError::NONE),
    192           ""));
    193   flow->OnAuthFlowTitleChange(GetFinalTitle("thisisjustabunchofjunk"));
    194 }
    195 
    196 TEST_F(IdentityGaiaWebAuthFlowTest, NoFragment) {
    197   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    198   flow->Start();
    199   // This won't be recognized as an interesting title.
    200   flow->OnAuthFlowTitleChange("Loading id.client.fake:/extension_id");
    201 }
    202 
    203 TEST_F(IdentityGaiaWebAuthFlowTest, Host) {
    204   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    205   flow->Start();
    206   // These won't be recognized as interesting titles.
    207   flow->OnAuthFlowTitleChange(
    208       "Loading id.client.fake://extension_id#access_token=fake_access_token");
    209   flow->OnAuthFlowTitleChange(
    210       "Loading id.client.fake://extension_id/#access_token=fake_access_token");
    211   flow->OnAuthFlowTitleChange(
    212       "Loading "
    213       "id.client.fake://host/extension_id/#access_token=fake_access_token");
    214 }
    215 
    216 TEST_F(IdentityGaiaWebAuthFlowTest, UbertokenFailure) {
    217   set_ubertoken_error(GoogleServiceAuthError::CONNECTION_FAILED);
    218   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    219   EXPECT_CALL(
    220       delegate_,
    221       OnGaiaFlowFailure(
    222           GaiaWebAuthFlow::SERVICE_AUTH_ERROR,
    223           GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
    224           ""));
    225   flow->Start();
    226 }
    227 
    228 TEST_F(IdentityGaiaWebAuthFlowTest, AuthFlowFailure) {
    229   scoped_ptr<TestGaiaWebAuthFlow> flow = CreateTestFlow();
    230   flow->Start();
    231   EXPECT_CALL(
    232       delegate_,
    233       OnGaiaFlowFailure(
    234           GaiaWebAuthFlow::WINDOW_CLOSED,
    235           GoogleServiceAuthError(GoogleServiceAuthError::NONE),
    236           ""));
    237   flow->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
    238 }
    239 
    240 }  // namespace extensions
    241