1// Copyright (c) 2011 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// A complete set of unit tests for GaiaAuthFetcher.
6// Originally ported from GoogleAuthenticator tests.
7
8#include <string>
9
10#include "base/message_loop.h"
11#include "base/string_util.h"
12#include "chrome/common/net/gaia/gaia_auth_consumer.h"
13#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
14#include "chrome/common/net/gaia/gaia_auth_fetcher_unittest.h"
15#include "chrome/common/net/gaia/google_service_auth_error.h"
16#include "chrome/common/net/http_return.h"
17#include "chrome/common/net/test_url_fetcher_factory.h"
18#include "chrome/common/net/url_fetcher.h"
19#include "chrome/test/testing_profile.h"
20#include "googleurl/src/gurl.h"
21#include "net/base/net_errors.h"
22#include "net/url_request/url_request_status.h"
23#include "testing/gmock/include/gmock/gmock.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
26using ::testing::_;
27
28MockFetcher::MockFetcher(bool success,
29                         const GURL& url,
30                         const std::string& results,
31                         URLFetcher::RequestType request_type,
32                         URLFetcher::Delegate* d)
33    : URLFetcher(url, request_type, d),
34      success_(success),
35      url_(url),
36      results_(results) {}
37
38MockFetcher::~MockFetcher() {}
39
40void MockFetcher::Start() {
41  net::URLRequestStatus::Status code;
42  int http_code;
43  if (success_) {
44    http_code = RC_REQUEST_OK;
45    code = net::URLRequestStatus::SUCCESS;
46  } else {
47    http_code = RC_FORBIDDEN;
48    code = net::URLRequestStatus::FAILED;
49  }
50
51  net::URLRequestStatus status(code, 0);
52  delegate()->OnURLFetchComplete(NULL,
53                                 url_,
54                                 status,
55                                 http_code,
56                                 ResponseCookies(),
57                                 results_);
58}
59
60
61class GaiaAuthFetcherTest : public testing::Test {
62 public:
63  GaiaAuthFetcherTest()
64      : client_login_source_(GaiaAuthFetcher::kClientLoginUrl),
65        issue_auth_token_source_(GaiaAuthFetcher::kIssueAuthTokenUrl) {}
66
67  void RunParsingTest(const std::string& data,
68                      const std::string& sid,
69                      const std::string& lsid,
70                      const std::string& token) {
71    std::string out_sid;
72    std::string out_lsid;
73    std::string out_token;
74
75    GaiaAuthFetcher::ParseClientLoginResponse(data,
76                                                 &out_sid,
77                                                 &out_lsid,
78                                                 &out_token);
79    EXPECT_EQ(lsid, out_lsid);
80    EXPECT_EQ(sid, out_sid);
81    EXPECT_EQ(token, out_token);
82  }
83
84  void RunErrorParsingTest(const std::string& data,
85                           const std::string& error,
86                           const std::string& error_url,
87                           const std::string& captcha_url,
88                           const std::string& captcha_token) {
89    std::string out_error;
90    std::string out_error_url;
91    std::string out_captcha_url;
92    std::string out_captcha_token;
93
94    GaiaAuthFetcher::ParseClientLoginFailure(data,
95                                                &out_error,
96                                                &out_error_url,
97                                                &out_captcha_url,
98                                                &out_captcha_token);
99    EXPECT_EQ(error, out_error);
100    EXPECT_EQ(error_url, out_error_url);
101    EXPECT_EQ(captcha_url, out_captcha_url);
102    EXPECT_EQ(captcha_token, out_captcha_token);
103  }
104
105  ResponseCookies cookies_;
106  GURL client_login_source_;
107  GURL issue_auth_token_source_;
108  TestingProfile profile_;
109 protected:
110  MessageLoop message_loop_;
111};
112
113class MockGaiaConsumer : public GaiaAuthConsumer {
114 public:
115  MockGaiaConsumer() {}
116  ~MockGaiaConsumer() {}
117
118  MOCK_METHOD1(OnClientLoginSuccess, void(const ClientLoginResult& result));
119  MOCK_METHOD2(OnIssueAuthTokenSuccess, void(const std::string& service,
120      const std::string& token));
121  MOCK_METHOD1(OnClientLoginFailure,
122      void(const GoogleServiceAuthError& error));
123  MOCK_METHOD2(OnIssueAuthTokenFailure, void(const std::string& service,
124      const GoogleServiceAuthError& error));
125};
126
127TEST_F(GaiaAuthFetcherTest, ErrorComparator) {
128  GoogleServiceAuthError expected_error =
129      GoogleServiceAuthError::FromConnectionError(-101);
130
131  GoogleServiceAuthError matching_error =
132      GoogleServiceAuthError::FromConnectionError(-101);
133
134  EXPECT_TRUE(expected_error == matching_error);
135
136  expected_error = GoogleServiceAuthError::FromConnectionError(6);
137
138  EXPECT_FALSE(expected_error == matching_error);
139
140  expected_error = GoogleServiceAuthError(GoogleServiceAuthError::NONE);
141
142  EXPECT_FALSE(expected_error == matching_error);
143
144  matching_error = GoogleServiceAuthError(GoogleServiceAuthError::NONE);
145
146  EXPECT_TRUE(expected_error == matching_error);
147}
148
149TEST_F(GaiaAuthFetcherTest, LoginNetFailure) {
150  int error_no = net::ERR_CONNECTION_RESET;
151  net::URLRequestStatus status(net::URLRequestStatus::FAILED, error_no);
152
153  GoogleServiceAuthError expected_error =
154      GoogleServiceAuthError::FromConnectionError(error_no);
155
156  MockGaiaConsumer consumer;
157  EXPECT_CALL(consumer, OnClientLoginFailure(expected_error))
158      .Times(1);
159
160  GaiaAuthFetcher auth(&consumer, std::string(),
161      profile_.GetRequestContext());
162
163  auth.OnURLFetchComplete(NULL,
164                          client_login_source_,
165                          status,
166                          0,
167                          cookies_,
168                          std::string());
169}
170
171TEST_F(GaiaAuthFetcherTest, TokenNetFailure) {
172  int error_no = net::ERR_CONNECTION_RESET;
173  net::URLRequestStatus status(net::URLRequestStatus::FAILED, error_no);
174
175  GoogleServiceAuthError expected_error =
176      GoogleServiceAuthError::FromConnectionError(error_no);
177
178  MockGaiaConsumer consumer;
179  EXPECT_CALL(consumer, OnIssueAuthTokenFailure(_, expected_error))
180      .Times(1);
181
182  GaiaAuthFetcher auth(&consumer, std::string(),
183      profile_.GetRequestContext());
184
185  auth.OnURLFetchComplete(NULL,
186                          issue_auth_token_source_,
187                          status,
188                          0,
189                          cookies_,
190                          std::string());
191}
192
193
194TEST_F(GaiaAuthFetcherTest, LoginDenied) {
195  std::string data("Error=BadAuthentication");
196  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
197
198  GoogleServiceAuthError expected_error(
199      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
200
201  MockGaiaConsumer consumer;
202  EXPECT_CALL(consumer, OnClientLoginFailure(expected_error))
203      .Times(1);
204
205  GaiaAuthFetcher auth(&consumer, std::string(),
206      profile_.GetRequestContext());
207  auth.OnURLFetchComplete(NULL,
208                          client_login_source_,
209                          status,
210                          RC_FORBIDDEN,
211                          cookies_,
212                          data);
213}
214
215TEST_F(GaiaAuthFetcherTest, ParseRequest) {
216  RunParsingTest("SID=sid\nLSID=lsid\nAuth=auth\n", "sid", "lsid", "auth");
217  RunParsingTest("LSID=lsid\nSID=sid\nAuth=auth\n", "sid", "lsid", "auth");
218  RunParsingTest("SID=sid\nLSID=lsid\nAuth=auth", "sid", "lsid", "auth");
219  RunParsingTest("SID=sid\nAuth=auth\n", "sid", "", "auth");
220  RunParsingTest("LSID=lsid\nAuth=auth\n", "", "lsid", "auth");
221  RunParsingTest("\nAuth=auth\n", "", "", "auth");
222  RunParsingTest("SID=sid", "sid", "", "");
223}
224
225TEST_F(GaiaAuthFetcherTest, ParseErrorRequest) {
226  RunErrorParsingTest("Url=U\n"
227                      "Error=E\n"
228                      "CaptchaToken=T\n"
229                      "CaptchaUrl=C\n", "E", "U", "C", "T");
230  RunErrorParsingTest("CaptchaToken=T\n"
231                      "Error=E\n"
232                      "Url=U\n"
233                      "CaptchaUrl=C\n", "E", "U", "C", "T");
234  RunErrorParsingTest("\n\n\nCaptchaToken=T\n"
235                      "\nError=E\n"
236                      "\nUrl=U\n"
237                      "CaptchaUrl=C\n", "E", "U", "C", "T");
238}
239
240
241TEST_F(GaiaAuthFetcherTest, OnlineLogin) {
242  std::string data("SID=sid\nLSID=lsid\nAuth=auth\n");
243
244  GaiaAuthConsumer::ClientLoginResult result;
245  result.lsid = "lsid";
246  result.sid = "sid";
247  result.token = "auth";
248  result.data = data;
249
250  MockGaiaConsumer consumer;
251  EXPECT_CALL(consumer, OnClientLoginSuccess(result))
252      .Times(1);
253
254  GaiaAuthFetcher auth(&consumer, std::string(),
255      profile_.GetRequestContext());
256  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
257  auth.OnURLFetchComplete(NULL,
258                          client_login_source_,
259                          status,
260                          RC_REQUEST_OK,
261                          cookies_,
262                          data);
263}
264
265TEST_F(GaiaAuthFetcherTest, WorkingIssueAuthToken) {
266  MockGaiaConsumer consumer;
267  EXPECT_CALL(consumer, OnIssueAuthTokenSuccess(_, "token"))
268      .Times(1);
269
270  GaiaAuthFetcher auth(&consumer, std::string(),
271      profile_.GetRequestContext());
272  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
273  auth.OnURLFetchComplete(NULL,
274                          issue_auth_token_source_,
275                          status,
276                          RC_REQUEST_OK,
277                          cookies_,
278                          "token");
279}
280
281TEST_F(GaiaAuthFetcherTest, CheckTwoFactorResponse) {
282  std::string response =
283      base::StringPrintf("Error=BadAuthentication\n%s\n",
284                         GaiaAuthFetcher::kSecondFactor);
285  EXPECT_TRUE(GaiaAuthFetcher::IsSecondFactorSuccess(response));
286}
287
288TEST_F(GaiaAuthFetcherTest, CheckNormalErrorCode) {
289  std::string response = "Error=BadAuthentication\n";
290  EXPECT_FALSE(GaiaAuthFetcher::IsSecondFactorSuccess(response));
291}
292
293TEST_F(GaiaAuthFetcherTest, TwoFactorLogin) {
294  std::string response = base::StringPrintf("Error=BadAuthentication\n%s\n",
295      GaiaAuthFetcher::kSecondFactor);
296
297  GoogleServiceAuthError error =
298      GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR);
299
300  MockGaiaConsumer consumer;
301  EXPECT_CALL(consumer, OnClientLoginFailure(error))
302      .Times(1);
303
304  GaiaAuthFetcher auth(&consumer, std::string(),
305      profile_.GetRequestContext());
306  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
307  auth.OnURLFetchComplete(NULL,
308                          client_login_source_,
309                          status,
310                          RC_FORBIDDEN,
311                          cookies_,
312                          response);
313}
314
315TEST_F(GaiaAuthFetcherTest, CaptchaParse) {
316  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
317  std::string data = "Url=http://www.google.com/login/captcha\n"
318                     "Error=CaptchaRequired\n"
319                     "CaptchaToken=CCTOKEN\n"
320                     "CaptchaUrl=Captcha?ctoken=CCTOKEN\n";
321  GoogleServiceAuthError error =
322      GaiaAuthFetcher::GenerateAuthError(data, status);
323
324  std::string token = "CCTOKEN";
325  GURL image_url("http://www.google.com/accounts/Captcha?ctoken=CCTOKEN");
326  GURL unlock_url("http://www.google.com/login/captcha");
327
328  EXPECT_EQ(error.state(), GoogleServiceAuthError::CAPTCHA_REQUIRED);
329  EXPECT_EQ(error.captcha().token, token);
330  EXPECT_EQ(error.captcha().image_url, image_url);
331  EXPECT_EQ(error.captcha().unlock_url, unlock_url);
332}
333
334TEST_F(GaiaAuthFetcherTest, AccountDeletedError) {
335  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
336  std::string data = "Error=AccountDeleted\n";
337  GoogleServiceAuthError error =
338      GaiaAuthFetcher::GenerateAuthError(data, status);
339  EXPECT_EQ(error.state(), GoogleServiceAuthError::ACCOUNT_DELETED);
340}
341
342TEST_F(GaiaAuthFetcherTest, AccountDisabledError) {
343  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
344  std::string data = "Error=AccountDisabled\n";
345  GoogleServiceAuthError error =
346      GaiaAuthFetcher::GenerateAuthError(data, status);
347  EXPECT_EQ(error.state(), GoogleServiceAuthError::ACCOUNT_DISABLED);
348}
349
350TEST_F(GaiaAuthFetcherTest,BadAuthenticationError) {
351  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
352  std::string data = "Error=BadAuthentication\n";
353  GoogleServiceAuthError error =
354      GaiaAuthFetcher::GenerateAuthError(data, status);
355  EXPECT_EQ(error.state(), GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
356}
357
358TEST_F(GaiaAuthFetcherTest,IncomprehensibleError) {
359  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
360  std::string data = "Error=Gobbledygook\n";
361  GoogleServiceAuthError error =
362      GaiaAuthFetcher::GenerateAuthError(data, status);
363  EXPECT_EQ(error.state(), GoogleServiceAuthError::SERVICE_UNAVAILABLE);
364}
365
366TEST_F(GaiaAuthFetcherTest,ServiceUnavailableError) {
367  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
368  std::string data = "Error=ServiceUnavailable\n";
369  GoogleServiceAuthError error =
370      GaiaAuthFetcher::GenerateAuthError(data, status);
371  EXPECT_EQ(error.state(), GoogleServiceAuthError::SERVICE_UNAVAILABLE);
372}
373
374TEST_F(GaiaAuthFetcherTest, FullLogin) {
375  MockGaiaConsumer consumer;
376  EXPECT_CALL(consumer, OnClientLoginSuccess(_))
377      .Times(1);
378
379  TestingProfile profile;
380
381  MockFactory<MockFetcher> factory;
382  URLFetcher::set_factory(&factory);
383
384  GaiaAuthFetcher auth(&consumer, std::string(),
385      profile_.GetRequestContext());
386  auth.StartClientLogin("username",
387                        "password",
388                        "service",
389                        std::string(),
390                        std::string(),
391                        GaiaAuthFetcher::HostedAccountsAllowed);
392
393  URLFetcher::set_factory(NULL);
394}
395
396TEST_F(GaiaAuthFetcherTest, FullLoginFailure) {
397  MockGaiaConsumer consumer;
398  EXPECT_CALL(consumer, OnClientLoginFailure(_))
399      .Times(1);
400
401  TestingProfile profile;
402
403  MockFactory<MockFetcher> factory;
404  URLFetcher::set_factory(&factory);
405  factory.set_success(false);
406
407  GaiaAuthFetcher auth(&consumer, std::string(),
408      profile_.GetRequestContext());
409  auth.StartClientLogin("username",
410                        "password",
411                        "service",
412                        std::string(),
413                        std::string(),
414                        GaiaAuthFetcher::HostedAccountsAllowed);
415
416  URLFetcher::set_factory(NULL);
417}
418
419TEST_F(GaiaAuthFetcherTest, ClientFetchPending) {
420  MockGaiaConsumer consumer;
421  EXPECT_CALL(consumer, OnClientLoginSuccess(_))
422      .Times(1);
423
424  TestingProfile profile;
425  TestURLFetcherFactory factory;
426  URLFetcher::set_factory(&factory);
427
428  GaiaAuthFetcher auth(&consumer, std::string(),
429      profile_.GetRequestContext());
430  auth.StartClientLogin("username",
431                        "password",
432                        "service",
433                        std::string(),
434                        std::string(),
435                        GaiaAuthFetcher::HostedAccountsAllowed);
436
437  URLFetcher::set_factory(NULL);
438  EXPECT_TRUE(auth.HasPendingFetch());
439  auth.OnURLFetchComplete(
440      NULL,
441      client_login_source_,
442      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0),
443      RC_REQUEST_OK,
444      cookies_,
445      "SID=sid\nLSID=lsid\nAuth=auth\n");
446  EXPECT_FALSE(auth.HasPendingFetch());
447}
448
449TEST_F(GaiaAuthFetcherTest, FullTokenSuccess) {
450  MockGaiaConsumer consumer;
451  EXPECT_CALL(consumer, OnIssueAuthTokenSuccess("service", "token"))
452      .Times(1);
453
454  TestingProfile profile;
455  TestURLFetcherFactory factory;
456  URLFetcher::set_factory(&factory);
457
458  GaiaAuthFetcher auth(&consumer, std::string(),
459      profile_.GetRequestContext());
460  auth.StartIssueAuthToken("sid", "lsid", "service");
461
462  URLFetcher::set_factory(NULL);
463  EXPECT_TRUE(auth.HasPendingFetch());
464  auth.OnURLFetchComplete(
465      NULL,
466      issue_auth_token_source_,
467      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0),
468      RC_REQUEST_OK,
469      cookies_,
470      "token");
471  EXPECT_FALSE(auth.HasPendingFetch());
472}
473
474TEST_F(GaiaAuthFetcherTest, FullTokenFailure) {
475  MockGaiaConsumer consumer;
476  EXPECT_CALL(consumer, OnIssueAuthTokenFailure("service", _))
477      .Times(1);
478
479  TestingProfile profile;
480  TestURLFetcherFactory factory;
481  URLFetcher::set_factory(&factory);
482
483  GaiaAuthFetcher auth(&consumer, std::string(),
484      profile_.GetRequestContext());
485  auth.StartIssueAuthToken("sid", "lsid", "service");
486
487  URLFetcher::set_factory(NULL);
488  EXPECT_TRUE(auth.HasPendingFetch());
489  auth.OnURLFetchComplete(
490      NULL,
491      issue_auth_token_source_,
492      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0),
493      RC_FORBIDDEN,
494      cookies_,
495      "");
496  EXPECT_FALSE(auth.HasPendingFetch());
497}
498