Chromium Code Reviews| 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..83a1e7c0d1bb2645409ea597ee98a117e600c777 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"; |
|
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.
|
| + |
| } // namespace |
| // TODO(chron): Add sourceless version of this formatter. |
| @@ -194,6 +210,7 @@ GaiaAuthFetcher::GaiaAuthFetcher(GaiaAuthConsumer* consumer, |
| GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(source)), |
| client_login_to_oauth2_gurl_( |
| GaiaUrls::GetInstance()->client_login_to_oauth2_url()), |
| + oauth2_iframe_url_(GaiaUrls::GetInstance()->oauth2_iframe_url()), |
| fetch_pending_(false) {} |
| GaiaAuthFetcher::~GaiaAuthFetcher() {} |
| @@ -422,6 +439,47 @@ 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. |
| + "ss_domain=%s&" |
| + "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(), |
| + 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. |
|
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.
|
| + "response_type=token+id_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 +542,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)) |
|
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
|
| + break; |
| + } |
| + |
| + if (login_hint->empty()) |
| + return false; |
| + return true; |
| +} |
| + |
| void GaiaAuthFetcher::StartClientLogin( |
| const std::string& username, |
| const std::string& password, |
| @@ -724,6 +815,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 +959,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 +1054,42 @@ 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; |
| + 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.
|
| + consumer_->OnListIdpSessionsSuccess(login_hint); |
| + } 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 +1133,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(); |
| } |