OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "google_apis/gaia/gaia_auth_fetcher.h" | 5 #include "google_apis/gaia/gaia_auth_fetcher.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 23 matching lines...) Expand all Loading... | |
34 static bool CookiePartsContains(const std::vector<std::string>& parts, | 34 static bool CookiePartsContains(const std::vector<std::string>& parts, |
35 const char* part) { | 35 const char* part) { |
36 for (std::vector<std::string>::const_iterator it = parts.begin(); | 36 for (std::vector<std::string>::const_iterator it = parts.begin(); |
37 it != parts.end(); ++it) { | 37 it != parts.end(); ++it) { |
38 if (LowerCaseEqualsASCII(*it, part)) | 38 if (LowerCaseEqualsASCII(*it, part)) |
39 return true; | 39 return true; |
40 } | 40 } |
41 return false; | 41 return false; |
42 } | 42 } |
43 | 43 |
44 bool ExtractOAuth2TokenPairResponse(base::DictionaryValue* dict, | 44 // From the JSON string |data|, extract the |access_token| and |expires_in_secs| |
45 // both of which must exist. If the |refresh_token| is non-NULL, then it also | |
46 // must exist and is extraced; if it's NULL, then no extraction is attempted. | |
47 bool ExtractOAuth2TokenPairResponse(const std::string& data, | |
45 std::string* refresh_token, | 48 std::string* refresh_token, |
46 std::string* access_token, | 49 std::string* access_token, |
47 int* expires_in_secs) { | 50 int* expires_in_secs) { |
48 DCHECK(refresh_token); | |
49 DCHECK(access_token); | 51 DCHECK(access_token); |
50 DCHECK(expires_in_secs); | 52 DCHECK(expires_in_secs); |
51 | 53 |
52 if (!dict->GetStringWithoutPathExpansion("refresh_token", refresh_token) || | 54 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
53 !dict->GetStringWithoutPathExpansion("access_token", access_token) || | 55 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) |
56 return false; | |
57 | |
58 base::DictionaryValue* dict = | |
59 static_cast<base::DictionaryValue*>(value.get()); | |
60 | |
61 if (!dict->GetStringWithoutPathExpansion("access_token", access_token) || | |
54 !dict->GetIntegerWithoutPathExpansion("expires_in", expires_in_secs)) { | 62 !dict->GetIntegerWithoutPathExpansion("expires_in", expires_in_secs)) { |
55 return false; | 63 return false; |
56 } | 64 } |
57 | 65 |
66 // Refresh token may not be required. | |
67 if (refresh_token) { | |
68 if (!dict->GetStringWithoutPathExpansion("refresh_token", refresh_token)) | |
69 return false; | |
70 } | |
58 return true; | 71 return true; |
59 } | 72 } |
60 | 73 |
74 const char* kListIdpServiceRequested = "list_idp"; | |
75 const char* kGetTokenResponseRequested = "get_token"; | |
Roger Tawa OOO till Jul 10th
2015/03/09 14:41:57
Use const char xxx[] = "..."; syntax.
Mike Lerman
2015/03/09 18:59:56
Done.
| |
76 | |
61 } // namespace | 77 } // namespace |
62 | 78 |
63 // TODO(chron): Add sourceless version of this formatter. | 79 // TODO(chron): Add sourceless version of this formatter. |
64 // static | 80 // static |
65 const char GaiaAuthFetcher::kClientLoginFormat[] = | 81 const char GaiaAuthFetcher::kClientLoginFormat[] = |
66 "Email=%s&" | 82 "Email=%s&" |
67 "Passwd=%s&" | 83 "Passwd=%s&" |
68 "PersistentCookie=%s&" | 84 "PersistentCookie=%s&" |
69 "accountType=%s&" | 85 "accountType=%s&" |
70 "source=%s&" | 86 "source=%s&" |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
187 merge_session_gurl_(GaiaUrls::GetInstance()->merge_session_url()), | 203 merge_session_gurl_(GaiaUrls::GetInstance()->merge_session_url()), |
188 uberauth_token_gurl_(GaiaUrls::GetInstance()->oauth1_login_url().Resolve( | 204 uberauth_token_gurl_(GaiaUrls::GetInstance()->oauth1_login_url().Resolve( |
189 base::StringPrintf(kUberAuthTokenURLFormat, source.c_str()))), | 205 base::StringPrintf(kUberAuthTokenURLFormat, source.c_str()))), |
190 oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()), | 206 oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()), |
191 list_accounts_gurl_( | 207 list_accounts_gurl_( |
192 GaiaUrls::GetInstance()->ListAccountsURLWithSource(source)), | 208 GaiaUrls::GetInstance()->ListAccountsURLWithSource(source)), |
193 get_check_connection_info_url_( | 209 get_check_connection_info_url_( |
194 GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(source)), | 210 GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(source)), |
195 client_login_to_oauth2_gurl_( | 211 client_login_to_oauth2_gurl_( |
196 GaiaUrls::GetInstance()->client_login_to_oauth2_url()), | 212 GaiaUrls::GetInstance()->client_login_to_oauth2_url()), |
213 oauth2_iframe_url_(GaiaUrls::GetInstance()->oauth2_iframe_url()), | |
197 fetch_pending_(false) {} | 214 fetch_pending_(false) {} |
198 | 215 |
199 GaiaAuthFetcher::~GaiaAuthFetcher() {} | 216 GaiaAuthFetcher::~GaiaAuthFetcher() {} |
200 | 217 |
201 bool GaiaAuthFetcher::HasPendingFetch() { | 218 bool GaiaAuthFetcher::HasPendingFetch() { |
202 return fetch_pending_; | 219 return fetch_pending_; |
203 } | 220 } |
204 | 221 |
205 void GaiaAuthFetcher::CancelRequest() { | 222 void GaiaAuthFetcher::CancelRequest() { |
206 fetcher_.reset(); | 223 fetcher_.reset(); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
415 std::string GaiaAuthFetcher::MakeOAuthLoginBody(const std::string& service, | 432 std::string GaiaAuthFetcher::MakeOAuthLoginBody(const std::string& service, |
416 const std::string& source) { | 433 const std::string& source) { |
417 std::string encoded_service = net::EscapeUrlEncodedData(service, true); | 434 std::string encoded_service = net::EscapeUrlEncodedData(service, true); |
418 std::string encoded_source = net::EscapeUrlEncodedData(source, true); | 435 std::string encoded_source = net::EscapeUrlEncodedData(source, true); |
419 return base::StringPrintf(kOAuthLoginFormat, | 436 return base::StringPrintf(kOAuthLoginFormat, |
420 encoded_service.c_str(), | 437 encoded_service.c_str(), |
421 encoded_source.c_str()); | 438 encoded_source.c_str()); |
422 } | 439 } |
423 | 440 |
424 // static | 441 // static |
442 std::string GaiaAuthFetcher::MakeListIDPSessionsBody( | |
443 const std::string& scopes, | |
444 const std::string& domain) { | |
445 static const char getTokenResponseBodyFormat[] = | |
446 "action=listSessions&" | |
447 "client_id=%s&" | |
448 "e=3100087&" // temporarily enable the experiment. | |
449 "ss_domain=%s&" | |
450 "origin=%s&" | |
451 "scope=%s"; | |
452 std::string encoded_client_id = net::EscapeUrlEncodedData( | |
453 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true); | |
454 return base::StringPrintf(getTokenResponseBodyFormat, | |
455 encoded_client_id.c_str(), | |
456 domain.c_str(), | |
457 domain.c_str(), | |
458 scopes.c_str()); | |
459 } | |
460 | |
461 std::string GaiaAuthFetcher::MakeGetTokenResponseBody( | |
462 const std::string& scopes, | |
463 const std::string& domain, | |
464 const std::string& login_hint) { | |
465 static const char getTokenResponseBodyFormat[] = | |
466 "action=issueToken&" | |
467 "client_id=%s&" | |
468 "login_hint=%s&" | |
469 "origin=%s&" | |
470 "e=3100087&" // temporarily enable the experiment. | |
Roger Tawa OOO till Jul 10th
2015/03/09 14:41:57
Nit: only 2 spaces between " and //. Same for li
Mike Lerman
2015/03/09 18:59:56
Done.
| |
471 "response_type=token+id_token&" | |
472 "scope=%s"; | |
473 std::string encoded_client_id = net::EscapeUrlEncodedData( | |
474 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true); | |
475 return base::StringPrintf(getTokenResponseBodyFormat, | |
476 encoded_client_id.c_str(), | |
477 login_hint.c_str(), | |
478 domain.c_str(), | |
479 scopes.c_str()); | |
480 } | |
481 | |
482 // static | |
425 void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data, | 483 void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data, |
426 std::string* error, | 484 std::string* error, |
427 std::string* error_url, | 485 std::string* error_url, |
428 std::string* captcha_url, | 486 std::string* captcha_url, |
429 std::string* captcha_token) { | 487 std::string* captcha_token) { |
430 using std::vector; | 488 using std::vector; |
431 using std::pair; | 489 using std::pair; |
432 using std::string; | 490 using std::string; |
433 | 491 |
434 vector<pair<string, string> > tokens; | 492 vector<pair<string, string> > tokens; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
477 if (StartsWithASCII( | 535 if (StartsWithASCII( |
478 part, kClientLoginToOAuth2CookiePartCodePrefix, false)) { | 536 part, kClientLoginToOAuth2CookiePartCodePrefix, false)) { |
479 auth_code->assign(part.substr( | 537 auth_code->assign(part.substr( |
480 kClientLoginToOAuth2CookiePartCodePrefixLength)); | 538 kClientLoginToOAuth2CookiePartCodePrefixLength)); |
481 return true; | 539 return true; |
482 } | 540 } |
483 } | 541 } |
484 return false; | 542 return false; |
485 } | 543 } |
486 | 544 |
545 // static | |
546 bool GaiaAuthFetcher::ParseListIdpSessionsResponse(const std::string& data, | |
547 std::string* login_hint) { | |
548 DCHECK(login_hint); | |
549 | |
550 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); | |
551 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) | |
552 return false; | |
553 | |
554 base::DictionaryValue* dict = | |
555 static_cast<base::DictionaryValue*>(value.get()); | |
556 | |
557 base::ListValue* sessionsList; | |
558 if (!dict->GetList("sessions", &sessionsList)) | |
559 return false; | |
560 | |
561 // Find the first login_hint present in any session. | |
562 for (base::ListValue::iterator iter = sessionsList->begin(); | |
563 iter != sessionsList->end(); | |
564 iter++) { | |
565 base::DictionaryValue* sessionDictionary; | |
566 if (!(*iter)->GetAsDictionary(&sessionDictionary)) | |
567 continue; | |
568 | |
569 if (sessionDictionary->GetString("login_hint", login_hint)) | |
Roger Tawa OOO till Jul 10th
2015/03/09 14:41:57
Should that be &login_hint ?
Mike Lerman
2015/03/09 18:59:56
It's already a pointer, so just login_hint should
| |
570 break; | |
571 } | |
572 | |
573 if (login_hint->empty()) | |
574 return false; | |
575 return true; | |
576 } | |
577 | |
487 void GaiaAuthFetcher::StartClientLogin( | 578 void GaiaAuthFetcher::StartClientLogin( |
488 const std::string& username, | 579 const std::string& username, |
489 const std::string& password, | 580 const std::string& password, |
490 const char* const service, | 581 const char* const service, |
491 const std::string& login_token, | 582 const std::string& login_token, |
492 const std::string& login_captcha, | 583 const std::string& login_captcha, |
493 HostedAccountsSetting allow_hosted_accounts) { | 584 HostedAccountsSetting allow_hosted_accounts) { |
494 | 585 |
495 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | 586 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; |
496 | 587 |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
717 fetcher_.reset(CreateGaiaFetcher(getter_, | 808 fetcher_.reset(CreateGaiaFetcher(getter_, |
718 std::string(), | 809 std::string(), |
719 std::string(), | 810 std::string(), |
720 get_check_connection_info_url_, | 811 get_check_connection_info_url_, |
721 kLoadFlagsIgnoreCookies, | 812 kLoadFlagsIgnoreCookies, |
722 this)); | 813 this)); |
723 fetch_pending_ = true; | 814 fetch_pending_ = true; |
724 fetcher_->Start(); | 815 fetcher_->Start(); |
725 } | 816 } |
726 | 817 |
818 void GaiaAuthFetcher::StartListIDPSessions(const std::string& scopes, | |
819 const std::string& domain) { | |
820 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
821 | |
822 request_body_ = MakeListIDPSessionsBody(scopes, domain); | |
823 fetcher_.reset(CreateGaiaFetcher(getter_, | |
824 request_body_, | |
825 std::string(), | |
826 oauth2_iframe_url_, | |
827 net::LOAD_NORMAL, | |
828 this)); | |
829 requested_service_ = kListIdpServiceRequested; | |
830 fetch_pending_ = true; | |
831 fetcher_->Start(); | |
832 } | |
833 | |
834 void GaiaAuthFetcher::StartGetTokenResponse(const std::string& scopes, | |
835 const std::string& domain, | |
836 const std::string& login_hint) { | |
837 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
838 | |
839 request_body_ = MakeGetTokenResponseBody(scopes, domain, login_hint); | |
840 fetcher_.reset(CreateGaiaFetcher(getter_, | |
841 request_body_, | |
842 std::string(), | |
843 oauth2_iframe_url_, | |
844 net::LOAD_NORMAL, | |
845 this)); | |
846 | |
847 requested_service_ = kGetTokenResponseRequested; | |
848 fetch_pending_ = true; | |
849 fetcher_->Start(); | |
850 } | |
851 | |
727 // static | 852 // static |
728 GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError( | 853 GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError( |
729 const std::string& data, | 854 const std::string& data, |
730 const net::URLRequestStatus& status) { | 855 const net::URLRequestStatus& status) { |
731 if (!status.is_success()) { | 856 if (!status.is_success()) { |
732 if (status.status() == net::URLRequestStatus::CANCELED) { | 857 if (status.status() == net::URLRequestStatus::CANCELED) { |
733 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); | 858 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); |
734 } | 859 } |
735 DLOG(WARNING) << "Could not reach Google Accounts servers: errno " | 860 DLOG(WARNING) << "Could not reach Google Accounts servers: errno " |
736 << status.error(); | 861 << status.error(); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
827 void GaiaAuthFetcher::OnOAuth2TokenPairFetched( | 952 void GaiaAuthFetcher::OnOAuth2TokenPairFetched( |
828 const std::string& data, | 953 const std::string& data, |
829 const net::URLRequestStatus& status, | 954 const net::URLRequestStatus& status, |
830 int response_code) { | 955 int response_code) { |
831 std::string refresh_token; | 956 std::string refresh_token; |
832 std::string access_token; | 957 std::string access_token; |
833 int expires_in_secs = 0; | 958 int expires_in_secs = 0; |
834 | 959 |
835 bool success = false; | 960 bool success = false; |
836 if (status.is_success() && response_code == net::HTTP_OK) { | 961 if (status.is_success() && response_code == net::HTTP_OK) { |
837 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); | 962 success = ExtractOAuth2TokenPairResponse(data, &refresh_token, |
838 if (value.get() && value->GetType() == base::Value::TYPE_DICTIONARY) { | |
839 base::DictionaryValue* dict = | |
840 static_cast<base::DictionaryValue*>(value.get()); | |
841 success = ExtractOAuth2TokenPairResponse(dict, &refresh_token, | |
842 &access_token, &expires_in_secs); | 963 &access_token, &expires_in_secs); |
843 } | |
844 } | 964 } |
845 | 965 |
846 if (success) { | 966 if (success) { |
847 consumer_->OnClientOAuthSuccess( | 967 consumer_->OnClientOAuthSuccess( |
848 GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token, | 968 GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token, |
849 expires_in_secs)); | 969 expires_in_secs)); |
850 } else { | 970 } else { |
851 consumer_->OnClientOAuthFailure(GenerateAuthError(data, status)); | 971 consumer_->OnClientOAuthFailure(GenerateAuthError(data, status)); |
852 } | 972 } |
853 } | 973 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
927 const std::string& data, | 1047 const std::string& data, |
928 const net::URLRequestStatus& status, | 1048 const net::URLRequestStatus& status, |
929 int response_code) { | 1049 int response_code) { |
930 if (status.is_success() && response_code == net::HTTP_OK) { | 1050 if (status.is_success() && response_code == net::HTTP_OK) { |
931 consumer_->OnGetCheckConnectionInfoSuccess(data); | 1051 consumer_->OnGetCheckConnectionInfoSuccess(data); |
932 } else { | 1052 } else { |
933 consumer_->OnGetCheckConnectionInfoError(GenerateAuthError(data, status)); | 1053 consumer_->OnGetCheckConnectionInfoError(GenerateAuthError(data, status)); |
934 } | 1054 } |
935 } | 1055 } |
936 | 1056 |
1057 void GaiaAuthFetcher::OnListIdpSessionsFetched( | |
1058 const std::string& data, | |
1059 const net::URLRequestStatus& status, | |
1060 int response_code) { | |
1061 if (status.is_success() && response_code == net::HTTP_OK) { | |
1062 DVLOG(1) << "ListIdpSessions successful!"; | |
1063 std::string login_hint; | |
1064 ParseListIdpSessionsResponse(data, &login_hint); | |
Roger Tawa OOO till Jul 10th
2015/03/09 14:41:57
If the parse fails, should call OnListIdpSessionsE
Mike Lerman
2015/03/09 18:59:56
Done.
| |
1065 consumer_->OnListIdpSessionsSuccess(login_hint); | |
1066 } else { | |
1067 consumer_->OnListIdpSessionsError(GenerateAuthError(data, status)); | |
1068 } | |
1069 } | |
1070 | |
1071 void GaiaAuthFetcher::OnGetTokenResponseFetched( | |
1072 const std::string& data, | |
1073 const net::URLRequestStatus& status, | |
1074 int response_code) { | |
1075 std::string access_token; | |
1076 int expires_in_secs = 0; | |
1077 bool success = false; | |
1078 if (status.is_success() && response_code == net::HTTP_OK) { | |
1079 DVLOG(1) << "GetTokenResponse successful!"; | |
1080 success = ExtractOAuth2TokenPairResponse(data, NULL, | |
1081 &access_token, &expires_in_secs); | |
1082 } | |
1083 | |
1084 if (success) { | |
1085 consumer_->OnGetTokenResponseSuccess( | |
1086 GaiaAuthConsumer::ClientOAuthResult(std::string(), access_token, | |
1087 expires_in_secs)); | |
1088 } else { | |
1089 consumer_->OnGetTokenResponseError(GenerateAuthError(data, status)); | |
1090 } | |
1091 } | |
1092 | |
937 void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { | 1093 void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { |
938 fetch_pending_ = false; | 1094 fetch_pending_ = false; |
939 // Some of the GAIA requests perform redirects, which results in the final | 1095 // Some of the GAIA requests perform redirects, which results in the final |
940 // URL of the fetcher not being the original URL requested. Therefore use | 1096 // URL of the fetcher not being the original URL requested. Therefore use |
941 // the original URL when determining which OnXXX function to call. | 1097 // the original URL when determining which OnXXX function to call. |
942 const GURL& url = source->GetOriginalURL(); | 1098 const GURL& url = source->GetOriginalURL(); |
943 const net::URLRequestStatus& status = source->GetStatus(); | 1099 const net::URLRequestStatus& status = source->GetStatus(); |
944 int response_code = source->GetResponseCode(); | 1100 int response_code = source->GetResponseCode(); |
945 std::string data; | 1101 std::string data; |
946 source->GetResponseAsString(&data); | 1102 source->GetResponseAsString(&data); |
(...skipping 23 matching lines...) Expand all Loading... | |
970 } else if (url == uberauth_token_gurl_) { | 1126 } else if (url == uberauth_token_gurl_) { |
971 OnUberAuthTokenFetch(data, status, response_code); | 1127 OnUberAuthTokenFetch(data, status, response_code); |
972 } else if (url == oauth_login_gurl_) { | 1128 } else if (url == oauth_login_gurl_) { |
973 OnOAuthLoginFetched(data, status, response_code); | 1129 OnOAuthLoginFetched(data, status, response_code); |
974 } else if (url == oauth2_revoke_gurl_) { | 1130 } else if (url == oauth2_revoke_gurl_) { |
975 OnOAuth2RevokeTokenFetched(data, status, response_code); | 1131 OnOAuth2RevokeTokenFetched(data, status, response_code); |
976 } else if (url == list_accounts_gurl_) { | 1132 } else if (url == list_accounts_gurl_) { |
977 OnListAccountsFetched(data, status, response_code); | 1133 OnListAccountsFetched(data, status, response_code); |
978 } else if (url == get_check_connection_info_url_) { | 1134 } else if (url == get_check_connection_info_url_) { |
979 OnGetCheckConnectionInfoFetched(data, status, response_code); | 1135 OnGetCheckConnectionInfoFetched(data, status, response_code); |
1136 } else if (url == oauth2_iframe_url_) { | |
1137 if (requested_service_ == kListIdpServiceRequested) | |
1138 OnListIdpSessionsFetched(data, status, response_code); | |
1139 else if (requested_service_ == kGetTokenResponseRequested) | |
1140 OnGetTokenResponseFetched(data, status, response_code); | |
1141 else | |
1142 NOTREACHED(); | |
980 } else { | 1143 } else { |
981 NOTREACHED(); | 1144 NOTREACHED(); |
982 } | 1145 } |
983 } | 1146 } |
984 | 1147 |
985 // static | 1148 // static |
986 bool GaiaAuthFetcher::IsSecondFactorSuccess( | 1149 bool GaiaAuthFetcher::IsSecondFactorSuccess( |
987 const std::string& alleged_error) { | 1150 const std::string& alleged_error) { |
988 return alleged_error.find(kSecondFactor) != | 1151 return alleged_error.find(kSecondFactor) != |
989 std::string::npos; | 1152 std::string::npos; |
990 } | 1153 } |
991 | 1154 |
992 // static | 1155 // static |
993 bool GaiaAuthFetcher::IsWebLoginRequiredSuccess( | 1156 bool GaiaAuthFetcher::IsWebLoginRequiredSuccess( |
994 const std::string& alleged_error) { | 1157 const std::string& alleged_error) { |
995 return alleged_error.find(kWebLoginRequired) != | 1158 return alleged_error.find(kWebLoginRequired) != |
996 std::string::npos; | 1159 std::string::npos; |
997 } | 1160 } |
OLD | NEW |