Index: google_apis/gaia/gaia_auth_fetcher.cc |
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc |
index 3b3c1902540489725987f862119e7e63f3a98f6a..224cb6c340bb202de347cc3ffdad24a8d0918600 100644 |
--- a/google_apis/gaia/gaia_auth_fetcher.cc |
+++ b/google_apis/gaia/gaia_auth_fetcher.cc |
@@ -41,23 +41,39 @@ static bool CookiePartsContains(const std::vector<std::string>& parts, |
return false; |
} |
-bool ExtractOAuth2TokenPairResponse(base::DictionaryValue* dict, |
+// From the JSON string |data|, extract the |access_token| and |expires_in_secs| |
+// both of which must exist. If the |refresh_token| is non-NULL, then it also |
+// must exist and is extraced; if it's NULL, then no extraction is attempted. |
+bool ExtractOAuth2TokenPairResponse(const std::string& data, |
std::string* refresh_token, |
std::string* access_token, |
int* expires_in_secs) { |
- DCHECK(refresh_token); |
DCHECK(access_token); |
DCHECK(expires_in_secs); |
- if (!dict->GetStringWithoutPathExpansion("refresh_token", refresh_token) || |
- !dict->GetStringWithoutPathExpansion("access_token", access_token) || |
+ scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
+ if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) |
+ return false; |
+ |
+ base::DictionaryValue* dict = |
+ static_cast<base::DictionaryValue*>(value.get()); |
+ |
+ if (!dict->GetStringWithoutPathExpansion("access_token", access_token) || |
!dict->GetIntegerWithoutPathExpansion("expires_in", expires_in_secs)) { |
return false; |
} |
+ // Refresh token may not be required. |
+ if (refresh_token) { |
+ if (!dict->GetStringWithoutPathExpansion("refresh_token", refresh_token)) |
+ return false; |
+ } |
return true; |
} |
+const char kListIdpServiceRequested[] = "list_idp"; |
+const char kGetTokenResponseRequested[] = "get_token"; |
+ |
} // namespace |
// TODO(chron): Add sourceless version of this formatter. |
@@ -192,6 +208,7 @@ GaiaAuthFetcher::GaiaAuthFetcher(GaiaAuthConsumer* consumer, |
GaiaUrls::GetInstance()->ListAccountsURLWithSource(source)), |
get_check_connection_info_url_( |
GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(source)), |
+ oauth2_iframe_url_(GaiaUrls::GetInstance()->oauth2_iframe_url()), |
client_login_to_oauth2_gurl_( |
GaiaUrls::GetInstance()->client_login_to_oauth2_url()), |
fetch_pending_(false) {} |
@@ -422,6 +439,45 @@ std::string GaiaAuthFetcher::MakeOAuthLoginBody(const std::string& service, |
} |
// static |
+std::string GaiaAuthFetcher::MakeListIDPSessionsBody( |
+ const std::string& scopes, |
+ const std::string& domain) { |
+ static const char getTokenResponseBodyFormat[] = |
+ "action=listSessions&" |
+ "client_id=%s&" |
+ "e=3100087&" // temporarily enable the experiment. |
+ "origin=%s&" |
+ "scope=%s"; |
+ std::string encoded_client_id = net::EscapeUrlEncodedData( |
+ GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true); |
+ return base::StringPrintf(getTokenResponseBodyFormat, |
+ encoded_client_id.c_str(), |
+ domain.c_str(), |
+ scopes.c_str()); |
+} |
+ |
+std::string GaiaAuthFetcher::MakeGetTokenResponseBody( |
+ const std::string& scopes, |
+ const std::string& domain, |
+ const std::string& login_hint) { |
+ static const char getTokenResponseBodyFormat[] = |
+ "action=issueToken&" |
+ "client_id=%s&" |
+ "login_hint=%s&" |
+ "origin=%s&" |
+ "e=3100087&" // temporarily enable the experiment. |
+ "response_type=token&" |
+ "scope=%s"; |
+ std::string encoded_client_id = net::EscapeUrlEncodedData( |
+ GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true); |
+ return base::StringPrintf(getTokenResponseBodyFormat, |
+ encoded_client_id.c_str(), |
+ login_hint.c_str(), |
+ domain.c_str(), |
+ scopes.c_str()); |
+} |
+ |
+// static |
void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data, |
std::string* error, |
std::string* error_url, |
@@ -484,6 +540,39 @@ bool GaiaAuthFetcher::ParseClientLoginToOAuth2Cookie(const std::string& cookie, |
return false; |
} |
+// static |
+bool GaiaAuthFetcher::ParseListIdpSessionsResponse(const std::string& data, |
+ std::string* login_hint) { |
+ DCHECK(login_hint); |
+ |
+ scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
+ if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) |
+ return false; |
+ |
+ base::DictionaryValue* dict = |
+ static_cast<base::DictionaryValue*>(value.get()); |
+ |
+ base::ListValue* sessionsList; |
+ if (!dict->GetList("sessions", &sessionsList)) |
+ return false; |
+ |
+ // Find the first login_hint present in any session. |
+ for (base::ListValue::iterator iter = sessionsList->begin(); |
+ iter != sessionsList->end(); |
+ iter++) { |
+ base::DictionaryValue* sessionDictionary; |
+ if (!(*iter)->GetAsDictionary(&sessionDictionary)) |
+ continue; |
+ |
+ if (sessionDictionary->GetString("login_hint", login_hint)) |
+ break; |
+ } |
+ |
+ if (login_hint->empty()) |
+ return false; |
+ return true; |
+} |
+ |
void GaiaAuthFetcher::StartClientLogin( |
const std::string& username, |
const std::string& password, |
@@ -724,6 +813,40 @@ void GaiaAuthFetcher::StartGetCheckConnectionInfo() { |
fetcher_->Start(); |
} |
+void GaiaAuthFetcher::StartListIDPSessions(const std::string& scopes, |
+ const std::string& domain) { |
+ DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; |
+ |
+ request_body_ = MakeListIDPSessionsBody(scopes, domain); |
+ fetcher_.reset(CreateGaiaFetcher(getter_, |
+ request_body_, |
+ std::string(), |
+ oauth2_iframe_url_, |
+ net::LOAD_NORMAL, |
+ this)); |
+ requested_service_ = kListIdpServiceRequested; |
+ fetch_pending_ = true; |
+ fetcher_->Start(); |
+} |
+ |
+void GaiaAuthFetcher::StartGetTokenResponse(const std::string& scopes, |
+ const std::string& domain, |
+ const std::string& login_hint) { |
+ DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; |
+ |
+ request_body_ = MakeGetTokenResponseBody(scopes, domain, login_hint); |
+ fetcher_.reset(CreateGaiaFetcher(getter_, |
+ request_body_, |
+ std::string(), |
+ oauth2_iframe_url_, |
+ net::LOAD_NORMAL, |
+ this)); |
+ |
+ requested_service_ = kGetTokenResponseRequested; |
+ fetch_pending_ = true; |
+ fetcher_->Start(); |
+} |
+ |
// static |
GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError( |
const std::string& data, |
@@ -834,13 +957,8 @@ void GaiaAuthFetcher::OnOAuth2TokenPairFetched( |
bool success = false; |
if (status.is_success() && response_code == net::HTTP_OK) { |
- scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
- if (value.get() && value->GetType() == base::Value::TYPE_DICTIONARY) { |
- base::DictionaryValue* dict = |
- static_cast<base::DictionaryValue*>(value.get()); |
- success = ExtractOAuth2TokenPairResponse(dict, &refresh_token, |
+ success = ExtractOAuth2TokenPairResponse(data, &refresh_token, |
&access_token, &expires_in_secs); |
- } |
} |
if (success) { |
@@ -934,6 +1052,48 @@ void GaiaAuthFetcher::OnGetCheckConnectionInfoFetched( |
} |
} |
+void GaiaAuthFetcher::OnListIdpSessionsFetched( |
+ const std::string& data, |
+ const net::URLRequestStatus& status, |
+ int response_code) { |
+ if (status.is_success() && response_code == net::HTTP_OK) { |
+ DVLOG(1) << "ListIdpSessions successful!"; |
+ std::string login_hint; |
+ if (ParseListIdpSessionsResponse(data, &login_hint)) { |
+ consumer_->OnListIdpSessionsSuccess(login_hint); |
+ } else { |
+ GoogleServiceAuthError auth_error( |
+ GoogleServiceAuthError::FromUnexpectedServiceResponse( |
+ "List Sessions response didn't contain a login_hint.")); |
+ consumer_->OnListIdpSessionsError(auth_error); |
+ } |
+ } else { |
+ consumer_->OnListIdpSessionsError(GenerateAuthError(data, status)); |
+ } |
+} |
+ |
+void GaiaAuthFetcher::OnGetTokenResponseFetched( |
+ const std::string& data, |
+ const net::URLRequestStatus& status, |
+ int response_code) { |
+ std::string access_token; |
+ int expires_in_secs = 0; |
+ bool success = false; |
+ if (status.is_success() && response_code == net::HTTP_OK) { |
+ DVLOG(1) << "GetTokenResponse successful!"; |
+ success = ExtractOAuth2TokenPairResponse(data, NULL, |
+ &access_token, &expires_in_secs); |
+ } |
+ |
+ if (success) { |
+ consumer_->OnGetTokenResponseSuccess( |
+ GaiaAuthConsumer::ClientOAuthResult(std::string(), access_token, |
+ expires_in_secs)); |
+ } else { |
+ consumer_->OnGetTokenResponseError(GenerateAuthError(data, status)); |
+ } |
+} |
+ |
void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { |
fetch_pending_ = false; |
// Some of the GAIA requests perform redirects, which results in the final |
@@ -977,6 +1137,13 @@ void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { |
OnListAccountsFetched(data, status, response_code); |
} else if (url == get_check_connection_info_url_) { |
OnGetCheckConnectionInfoFetched(data, status, response_code); |
+ } else if (url == oauth2_iframe_url_) { |
+ if (requested_service_ == kListIdpServiceRequested) |
+ OnListIdpSessionsFetched(data, status, response_code); |
+ else if (requested_service_ == kGetTokenResponseRequested) |
+ OnGetTokenResponseFetched(data, status, response_code); |
+ else |
+ NOTREACHED(); |
} else { |
NOTREACHED(); |
} |