oauth2_mint_token_flow.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/oauth2_mint_token_flow.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::URLFetcher;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::URLRequestContextGetter;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::URLRequestStatus;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kForceValueFalse[] = "false";
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kForceValueTrue[] = "true";
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kResponseTypeValueNone[] = "none";
3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kResponseTypeValueToken[] = "token";
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kOAuth2IssueTokenBodyFormat[] =
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "force=%s"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "&response_type=%s"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "&scope=%s"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "&client_id=%s"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "&origin=%s";
4468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kIssueAdviceKey[] = "issueAdvice";
4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kIssueAdviceValueConsent[] = "consent";
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kAccessTokenKey[] = "token";
4768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kConsentKey[] = "consent";
4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kExpiresInKey[] = "expiresIn";
4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kScopesKey[] = "scopes";
5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kDescriptionKey[] = "description";
5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kDetailKey[] = "detail";
5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kDetailSeparators[] = "\n";
5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kError[] = "error";
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kMessage[] = "message";
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic GoogleServiceAuthError CreateAuthError(const net::URLFetcher* source) {
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  URLRequestStatus status = source->GetStatus();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.status() == URLRequestStatus::CANCELED) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (status.status() == URLRequestStatus::FAILED) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Server returned error: errno " << status.error();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError::FromConnectionError(status.error());
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string response_body;
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  source->GetResponseAsString(&response_body);
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(response_body));
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* response;
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!value.get() || !value->GetAsDictionary(&response)) {
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return GoogleServiceAuthError::FromUnexpectedServiceResponse(
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        base::StringPrintf(
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            "Not able to parse a JSON object from a service response. "
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            "HTTP Status of the response is: %d", source->GetResponseCode()));
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* error;
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!response->GetDictionary(kError, &error)) {
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return GoogleServiceAuthError::FromUnexpectedServiceResponse(
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "Not able to find a detailed error in a service response.");
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string message;
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!error->GetString(kMessage, &message)) {
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return GoogleServiceAuthError::FromUnexpectedServiceResponse(
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "Not able to find an error message within a service error.");
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return GoogleServiceAuthError::FromServiceError(message);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IssueAdviceInfoEntry::IssueAdviceInfoEntry() {}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IssueAdviceInfoEntry::~IssueAdviceInfoEntry() {}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IssueAdviceInfoEntry::operator ==(const IssueAdviceInfoEntry& rhs) const {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return description == rhs.description && details == rhs.details;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OAuth2MintTokenFlow::Parameters::Parameters() : mode(MODE_ISSUE_ADVICE) {}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OAuth2MintTokenFlow::Parameters::Parameters(
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& at,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& eid,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& cid,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<std::string>& scopes_arg,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Mode mode_arg)
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    : access_token(at),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_id(eid),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_id(cid),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scopes(scopes_arg),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mode(mode_arg) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OAuth2MintTokenFlow::Parameters::~Parameters() {}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)OAuth2MintTokenFlow::OAuth2MintTokenFlow(URLRequestContextGetter* context,
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                         Delegate* delegate,
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                         const Parameters& parameters)
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : OAuth2ApiCallFlow(context,
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        std::string(),
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        parameters.access_token,
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        std::vector<std::string>()),
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate),
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parameters_(parameters),
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OAuth2MintTokenFlow::~OAuth2MintTokenFlow() { }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void OAuth2MintTokenFlow::ReportSuccess(const std::string& access_token,
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        int time_to_live) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delegate_->OnMintTokenSuccess(access_token, time_to_live);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |this| may already be deleted.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2MintTokenFlow::ReportIssueAdviceSuccess(
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const IssueAdviceInfo& issue_advice) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnIssueAdviceSuccess(issue_advice);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |this| may already be deleted.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2MintTokenFlow::ReportFailure(
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GoogleServiceAuthError& error) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnMintTokenFailure(error);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |this| may already be deleted.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL OAuth2MintTokenFlow::CreateApiCallUrl() {
153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return GaiaUrls::GetInstance()->oauth2_issue_token_url();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string OAuth2MintTokenFlow::CreateApiCallBody() {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* force_value =
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (parameters_.mode == MODE_MINT_TOKEN_FORCE ||
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       parameters_.mode == MODE_RECORD_GRANT)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ? kForceValueTrue : kForceValueFalse;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* response_type_value =
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (parameters_.mode == MODE_MINT_TOKEN_NO_FORCE ||
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       parameters_.mode == MODE_MINT_TOKEN_FORCE)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ? kResponseTypeValueToken : kResponseTypeValueNone;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf(
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kOAuth2IssueTokenBodyFormat,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::EscapeUrlEncodedData(force_value, true).c_str(),
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::EscapeUrlEncodedData(response_type_value, true).c_str(),
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::EscapeUrlEncodedData(
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          JoinString(parameters_.scopes, ' '), true).c_str(),
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::EscapeUrlEncodedData(parameters_.client_id, true).c_str(),
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::EscapeUrlEncodedData(parameters_.extension_id, true).c_str());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2MintTokenFlow::ProcessApiCallSuccess(
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string response_body;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source->GetResponseAsString(&response_body);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(response_body));
180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::DictionaryValue* dict = NULL;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.get() || !value->GetAsDictionary(&dict)) {
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "Not able to parse a JSON object from a service response."));
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string issue_advice_value;
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!dict->GetString(kIssueAdviceKey, &issue_advice_value)) {
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "Not able to find an issueAdvice in a service response."));
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (issue_advice_value == kIssueAdviceValueConsent) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IssueAdviceInfo issue_advice;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ParseIssueAdviceResponse(dict, &issue_advice))
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportIssueAdviceSuccess(issue_advice);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          "Not able to parse the contents of consent "
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          "from a service response."));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string access_token;
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int time_to_live;
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (ParseMintTokenResponse(dict, &access_token, &time_to_live))
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReportSuccess(access_token, time_to_live);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          "Not able to parse the contents of access token "
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          "from a service response."));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |this| may be deleted!
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2MintTokenFlow::ProcessApiCallFailure(
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source) {
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ReportFailure(CreateAuthError(source));
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2MintTokenFlow::ProcessNewAccessToken(
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& access_token) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't currently store new access tokens. We generate one every time.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // So we have nothing to do here.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OAuth2MintTokenFlow::ProcessMintAccessTokenFailure(
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GoogleServiceAuthError& error) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportFailure(error);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OAuth2MintTokenFlow::ParseMintTokenResponse(
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::DictionaryValue* dict, std::string* access_token,
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int* time_to_live) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(dict);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(access_token);
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(time_to_live);
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string ttl_string;
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return dict->GetString(kExpiresInKey, &ttl_string) &&
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::StringToInt(ttl_string, time_to_live) &&
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      dict->GetString(kAccessTokenKey, access_token);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OAuth2MintTokenFlow::ParseIssueAdviceResponse(
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue* dict, IssueAdviceInfo* issue_advice) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(dict);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(issue_advice);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::DictionaryValue* consent_dict = NULL;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dict->GetDictionary(kConsentKey, &consent_dict))
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::ListValue* scopes_list = NULL;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!consent_dict->GetList(kScopesKey, &scopes_list))
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = true;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t index = 0; index < scopes_list->GetSize(); ++index) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue* scopes_entry = NULL;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IssueAdviceInfoEntry entry;
261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 detail;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!scopes_list->GetDictionary(index, &scopes_entry) ||
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !scopes_entry->GetString(kDescriptionKey, &entry.description) ||
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !scopes_entry->GetString(kDetailKey, &detail)) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = false;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TrimWhitespace(entry.description, TRIM_ALL, &entry.description);
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    static const base::string16 detail_separators =
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::ASCIIToUTF16(kDetailSeparators);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tokenize(detail, detail_separators, &entry.details);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < entry.details.size(); i++)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TrimWhitespace(entry.details[i], TRIM_ALL, &entry.details[i]);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    issue_advice->push_back(entry);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!success)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    issue_advice->clear();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
283