Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(440)

Side by Side Diff: google_apis/gaia/gaia_auth_fetcher.cc

Issue 973953002: Implement the calls to GAIA for the IDP IFrame protocol. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Roger and Guibin's nits and comments Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « google_apis/gaia/gaia_auth_fetcher.h ('k') | google_apis/gaia/gaia_auth_fetcher_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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";
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 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 oauth2_revoke_gurl_(GaiaUrls::GetInstance()->oauth2_revoke_url()), 201 oauth2_revoke_gurl_(GaiaUrls::GetInstance()->oauth2_revoke_url()),
186 get_user_info_gurl_(GaiaUrls::GetInstance()->get_user_info_url()), 202 get_user_info_gurl_(GaiaUrls::GetInstance()->get_user_info_url()),
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)),
211 oauth2_iframe_url_(GaiaUrls::GetInstance()->oauth2_iframe_url()),
195 client_login_to_oauth2_gurl_( 212 client_login_to_oauth2_gurl_(
196 GaiaUrls::GetInstance()->client_login_to_oauth2_url()), 213 GaiaUrls::GetInstance()->client_login_to_oauth2_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
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 "origin=%s&"
450 "scope=%s";
451 std::string encoded_client_id = net::EscapeUrlEncodedData(
452 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true);
453 return base::StringPrintf(getTokenResponseBodyFormat,
454 encoded_client_id.c_str(),
455 domain.c_str(),
456 scopes.c_str());
457 }
458
459 std::string GaiaAuthFetcher::MakeGetTokenResponseBody(
460 const std::string& scopes,
461 const std::string& domain,
462 const std::string& login_hint) {
463 static const char getTokenResponseBodyFormat[] =
464 "action=issueToken&"
465 "client_id=%s&"
466 "login_hint=%s&"
467 "origin=%s&"
468 "e=3100087&" // temporarily enable the experiment.
469 "response_type=token&"
470 "scope=%s";
471 std::string encoded_client_id = net::EscapeUrlEncodedData(
472 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true);
473 return base::StringPrintf(getTokenResponseBodyFormat,
474 encoded_client_id.c_str(),
475 login_hint.c_str(),
476 domain.c_str(),
477 scopes.c_str());
478 }
479
480 // static
425 void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data, 481 void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data,
426 std::string* error, 482 std::string* error,
427 std::string* error_url, 483 std::string* error_url,
428 std::string* captcha_url, 484 std::string* captcha_url,
429 std::string* captcha_token) { 485 std::string* captcha_token) {
430 using std::vector; 486 using std::vector;
431 using std::pair; 487 using std::pair;
432 using std::string; 488 using std::string;
433 489
434 vector<pair<string, string> > tokens; 490 vector<pair<string, string> > tokens;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 if (StartsWithASCII( 533 if (StartsWithASCII(
478 part, kClientLoginToOAuth2CookiePartCodePrefix, false)) { 534 part, kClientLoginToOAuth2CookiePartCodePrefix, false)) {
479 auth_code->assign(part.substr( 535 auth_code->assign(part.substr(
480 kClientLoginToOAuth2CookiePartCodePrefixLength)); 536 kClientLoginToOAuth2CookiePartCodePrefixLength));
481 return true; 537 return true;
482 } 538 }
483 } 539 }
484 return false; 540 return false;
485 } 541 }
486 542
543 // static
544 bool GaiaAuthFetcher::ParseListIdpSessionsResponse(const std::string& data,
545 std::string* login_hint) {
546 DCHECK(login_hint);
547
548 scoped_ptr<base::Value> value(base::JSONReader::Read(data));
549 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY)
550 return false;
551
552 base::DictionaryValue* dict =
553 static_cast<base::DictionaryValue*>(value.get());
554
555 base::ListValue* sessionsList;
556 if (!dict->GetList("sessions", &sessionsList))
557 return false;
558
559 // Find the first login_hint present in any session.
560 for (base::ListValue::iterator iter = sessionsList->begin();
561 iter != sessionsList->end();
562 iter++) {
563 base::DictionaryValue* sessionDictionary;
564 if (!(*iter)->GetAsDictionary(&sessionDictionary))
565 continue;
566
567 if (sessionDictionary->GetString("login_hint", login_hint))
568 break;
569 }
570
571 if (login_hint->empty())
572 return false;
573 return true;
574 }
575
487 void GaiaAuthFetcher::StartClientLogin( 576 void GaiaAuthFetcher::StartClientLogin(
488 const std::string& username, 577 const std::string& username,
489 const std::string& password, 578 const std::string& password,
490 const char* const service, 579 const char* const service,
491 const std::string& login_token, 580 const std::string& login_token,
492 const std::string& login_captcha, 581 const std::string& login_captcha,
493 HostedAccountsSetting allow_hosted_accounts) { 582 HostedAccountsSetting allow_hosted_accounts) {
494 583
495 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; 584 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
496 585
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
717 fetcher_.reset(CreateGaiaFetcher(getter_, 806 fetcher_.reset(CreateGaiaFetcher(getter_,
718 std::string(), 807 std::string(),
719 std::string(), 808 std::string(),
720 get_check_connection_info_url_, 809 get_check_connection_info_url_,
721 kLoadFlagsIgnoreCookies, 810 kLoadFlagsIgnoreCookies,
722 this)); 811 this));
723 fetch_pending_ = true; 812 fetch_pending_ = true;
724 fetcher_->Start(); 813 fetcher_->Start();
725 } 814 }
726 815
816 void GaiaAuthFetcher::StartListIDPSessions(const std::string& scopes,
817 const std::string& domain) {
818 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
819
820 request_body_ = MakeListIDPSessionsBody(scopes, domain);
821 fetcher_.reset(CreateGaiaFetcher(getter_,
822 request_body_,
823 std::string(),
824 oauth2_iframe_url_,
825 net::LOAD_NORMAL,
826 this));
827 requested_service_ = kListIdpServiceRequested;
828 fetch_pending_ = true;
829 fetcher_->Start();
830 }
831
832 void GaiaAuthFetcher::StartGetTokenResponse(const std::string& scopes,
833 const std::string& domain,
834 const std::string& login_hint) {
835 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
836
837 request_body_ = MakeGetTokenResponseBody(scopes, domain, login_hint);
838 fetcher_.reset(CreateGaiaFetcher(getter_,
839 request_body_,
840 std::string(),
841 oauth2_iframe_url_,
842 net::LOAD_NORMAL,
843 this));
844
845 requested_service_ = kGetTokenResponseRequested;
846 fetch_pending_ = true;
847 fetcher_->Start();
848 }
849
727 // static 850 // static
728 GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError( 851 GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError(
729 const std::string& data, 852 const std::string& data,
730 const net::URLRequestStatus& status) { 853 const net::URLRequestStatus& status) {
731 if (!status.is_success()) { 854 if (!status.is_success()) {
732 if (status.status() == net::URLRequestStatus::CANCELED) { 855 if (status.status() == net::URLRequestStatus::CANCELED) {
733 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); 856 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
734 } 857 }
735 DLOG(WARNING) << "Could not reach Google Accounts servers: errno " 858 DLOG(WARNING) << "Could not reach Google Accounts servers: errno "
736 << status.error(); 859 << status.error();
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 void GaiaAuthFetcher::OnOAuth2TokenPairFetched( 950 void GaiaAuthFetcher::OnOAuth2TokenPairFetched(
828 const std::string& data, 951 const std::string& data,
829 const net::URLRequestStatus& status, 952 const net::URLRequestStatus& status,
830 int response_code) { 953 int response_code) {
831 std::string refresh_token; 954 std::string refresh_token;
832 std::string access_token; 955 std::string access_token;
833 int expires_in_secs = 0; 956 int expires_in_secs = 0;
834 957
835 bool success = false; 958 bool success = false;
836 if (status.is_success() && response_code == net::HTTP_OK) { 959 if (status.is_success() && response_code == net::HTTP_OK) {
837 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); 960 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); 961 &access_token, &expires_in_secs);
843 }
844 } 962 }
845 963
846 if (success) { 964 if (success) {
847 consumer_->OnClientOAuthSuccess( 965 consumer_->OnClientOAuthSuccess(
848 GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token, 966 GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token,
849 expires_in_secs)); 967 expires_in_secs));
850 } else { 968 } else {
851 consumer_->OnClientOAuthFailure(GenerateAuthError(data, status)); 969 consumer_->OnClientOAuthFailure(GenerateAuthError(data, status));
852 } 970 }
853 } 971 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 const std::string& data, 1045 const std::string& data,
928 const net::URLRequestStatus& status, 1046 const net::URLRequestStatus& status,
929 int response_code) { 1047 int response_code) {
930 if (status.is_success() && response_code == net::HTTP_OK) { 1048 if (status.is_success() && response_code == net::HTTP_OK) {
931 consumer_->OnGetCheckConnectionInfoSuccess(data); 1049 consumer_->OnGetCheckConnectionInfoSuccess(data);
932 } else { 1050 } else {
933 consumer_->OnGetCheckConnectionInfoError(GenerateAuthError(data, status)); 1051 consumer_->OnGetCheckConnectionInfoError(GenerateAuthError(data, status));
934 } 1052 }
935 } 1053 }
936 1054
1055 void GaiaAuthFetcher::OnListIdpSessionsFetched(
1056 const std::string& data,
1057 const net::URLRequestStatus& status,
1058 int response_code) {
1059 if (status.is_success() && response_code == net::HTTP_OK) {
1060 DVLOG(1) << "ListIdpSessions successful!";
1061 std::string login_hint;
1062 if (ParseListIdpSessionsResponse(data, &login_hint)) {
1063 consumer_->OnListIdpSessionsSuccess(login_hint);
1064 } else {
1065 GoogleServiceAuthError auth_error(
1066 GoogleServiceAuthError::FromUnexpectedServiceResponse(
1067 "List Sessions response didn't contain a login_hint."));
1068 consumer_->OnListIdpSessionsError(auth_error);
1069 }
1070 } else {
1071 consumer_->OnListIdpSessionsError(GenerateAuthError(data, status));
1072 }
1073 }
1074
1075 void GaiaAuthFetcher::OnGetTokenResponseFetched(
1076 const std::string& data,
1077 const net::URLRequestStatus& status,
1078 int response_code) {
1079 std::string access_token;
1080 int expires_in_secs = 0;
1081 bool success = false;
1082 if (status.is_success() && response_code == net::HTTP_OK) {
1083 DVLOG(1) << "GetTokenResponse successful!";
1084 success = ExtractOAuth2TokenPairResponse(data, NULL,
1085 &access_token, &expires_in_secs);
1086 }
1087
1088 if (success) {
1089 consumer_->OnGetTokenResponseSuccess(
1090 GaiaAuthConsumer::ClientOAuthResult(std::string(), access_token,
1091 expires_in_secs));
1092 } else {
1093 consumer_->OnGetTokenResponseError(GenerateAuthError(data, status));
1094 }
1095 }
1096
937 void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { 1097 void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
938 fetch_pending_ = false; 1098 fetch_pending_ = false;
939 // Some of the GAIA requests perform redirects, which results in the final 1099 // 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 1100 // URL of the fetcher not being the original URL requested. Therefore use
941 // the original URL when determining which OnXXX function to call. 1101 // the original URL when determining which OnXXX function to call.
942 const GURL& url = source->GetOriginalURL(); 1102 const GURL& url = source->GetOriginalURL();
943 const net::URLRequestStatus& status = source->GetStatus(); 1103 const net::URLRequestStatus& status = source->GetStatus();
944 int response_code = source->GetResponseCode(); 1104 int response_code = source->GetResponseCode();
945 std::string data; 1105 std::string data;
946 source->GetResponseAsString(&data); 1106 source->GetResponseAsString(&data);
(...skipping 23 matching lines...) Expand all
970 } else if (url == uberauth_token_gurl_) { 1130 } else if (url == uberauth_token_gurl_) {
971 OnUberAuthTokenFetch(data, status, response_code); 1131 OnUberAuthTokenFetch(data, status, response_code);
972 } else if (url == oauth_login_gurl_) { 1132 } else if (url == oauth_login_gurl_) {
973 OnOAuthLoginFetched(data, status, response_code); 1133 OnOAuthLoginFetched(data, status, response_code);
974 } else if (url == oauth2_revoke_gurl_) { 1134 } else if (url == oauth2_revoke_gurl_) {
975 OnOAuth2RevokeTokenFetched(data, status, response_code); 1135 OnOAuth2RevokeTokenFetched(data, status, response_code);
976 } else if (url == list_accounts_gurl_) { 1136 } else if (url == list_accounts_gurl_) {
977 OnListAccountsFetched(data, status, response_code); 1137 OnListAccountsFetched(data, status, response_code);
978 } else if (url == get_check_connection_info_url_) { 1138 } else if (url == get_check_connection_info_url_) {
979 OnGetCheckConnectionInfoFetched(data, status, response_code); 1139 OnGetCheckConnectionInfoFetched(data, status, response_code);
1140 } else if (url == oauth2_iframe_url_) {
1141 if (requested_service_ == kListIdpServiceRequested)
1142 OnListIdpSessionsFetched(data, status, response_code);
1143 else if (requested_service_ == kGetTokenResponseRequested)
1144 OnGetTokenResponseFetched(data, status, response_code);
1145 else
1146 NOTREACHED();
980 } else { 1147 } else {
981 NOTREACHED(); 1148 NOTREACHED();
982 } 1149 }
983 } 1150 }
984 1151
985 // static 1152 // static
986 bool GaiaAuthFetcher::IsSecondFactorSuccess( 1153 bool GaiaAuthFetcher::IsSecondFactorSuccess(
987 const std::string& alleged_error) { 1154 const std::string& alleged_error) {
988 return alleged_error.find(kSecondFactor) != 1155 return alleged_error.find(kSecondFactor) !=
989 std::string::npos; 1156 std::string::npos;
990 } 1157 }
991 1158
992 // static 1159 // static
993 bool GaiaAuthFetcher::IsWebLoginRequiredSuccess( 1160 bool GaiaAuthFetcher::IsWebLoginRequiredSuccess(
994 const std::string& alleged_error) { 1161 const std::string& alleged_error) {
995 return alleged_error.find(kWebLoginRequired) != 1162 return alleged_error.find(kWebLoginRequired) !=
996 std::string::npos; 1163 std::string::npos;
997 } 1164 }
OLDNEW
« no previous file with comments | « google_apis/gaia/gaia_auth_fetcher.h ('k') | google_apis/gaia/gaia_auth_fetcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698