190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/debug/trace_event.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/strings/string_split.h"
105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
135b892326406927b709cdaf6c384d4ababf456332Ben Murdoch#include "chrome/browser/signin/chrome_signin_client_factory.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/profile_oauth2_token_service.h"
17e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/signin_manager.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "net/base/escape.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace extensions {
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)GaiaWebAuthFlow::GaiaWebAuthFlow(Delegate* delegate,
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 Profile* profile,
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 const ExtensionTokenKey* token_key,
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                 const std::string& oauth2_client_id,
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 const std::string& locale)
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : delegate_(delegate),
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      profile_(profile),
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      account_id_(token_key->account_id) {
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_BEGIN2("identity",
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           "GaiaWebAuthFlow",
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           this,
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           "extension_id",
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           token_key->extension_id,
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           "account_id",
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           token_key->account_id);
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kOAuth2RedirectPathFormat[] = "/%s#";
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kOAuth2AuthorizeFormat[] =
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      "?response_type=token&approval_prompt=force&authuser=0&"
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      "client_id=%s&"
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      "scope=%s&"
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      "origin=chrome-extension://%s/&"
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      "redirect_uri=%s:/%s&"
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      "hl=%s";
475b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  // Additional parameters to pass if device_id is enabled.
485b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  const char kOAuth2AuthorizeFormatDeviceIdAddendum[] =
495b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      "&device_id=%s&"
505b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      "device_type=chrome";
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<std::string> scopes(token_key->scopes.begin(),
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  token_key->scopes.end());
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<std::string> client_id_parts;
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::SplitString(oauth2_client_id, '.', &client_id_parts);
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::reverse(client_id_parts.begin(), client_id_parts.end());
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  redirect_scheme_ = JoinString(client_id_parts, '.');
585b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  std::string signin_scoped_device_id;
595b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  // profile_ can be nullptr in unittests.
605b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  SigninClient* signin_client =
615b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      profile_ ? ChromeSigninClientFactory::GetForProfile(profile_) : nullptr;
625b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  if (signin_client)
635b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    signin_scoped_device_id = signin_client->GetSigninScopedDeviceId();
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  redirect_path_prefix_ = base::StringPrintf(kOAuth2RedirectPathFormat,
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                             token_key->extension_id.c_str());
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
685b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  std::string oauth2_authorize_params = base::StringPrintf(
695b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      kOAuth2AuthorizeFormat,
705b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      oauth2_client_id.c_str(),
715b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      net::EscapeUrlEncodedData(JoinString(scopes, ' '), true).c_str(),
725b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      token_key->extension_id.c_str(),
735b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      redirect_scheme_.c_str(),
745b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      token_key->extension_id.c_str(),
755b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      locale.c_str());
765b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  if (!signin_scoped_device_id.empty()) {
775b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    oauth2_authorize_params += base::StringPrintf(
785b892326406927b709cdaf6c384d4ababf456332Ben Murdoch        kOAuth2AuthorizeFormatDeviceIdAddendum,
795b892326406927b709cdaf6c384d4ababf456332Ben Murdoch        net::EscapeUrlEncodedData(signin_scoped_device_id, true).c_str());
805b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  }
815b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  auth_url_ = GaiaUrls::GetInstance()->oauth2_auth_url().Resolve(
825b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      oauth2_authorize_params);
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)GaiaWebAuthFlow::~GaiaWebAuthFlow() {
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_END0("identity", "GaiaWebAuthFlow", this);
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (web_flow_)
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    web_flow_.release()->DetachDelegateAndDelete();
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GaiaWebAuthFlow::Start() {
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProfileOAuth2TokenService* token_service =
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ubertoken_fetcher_.reset(new UbertokenFetcher(token_service,
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                this,
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                profile_->GetRequestContext()));
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ubertoken_fetcher_->StartFetchingToken(account_id_);
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GaiaWebAuthFlow::OnUbertokenSuccess(const std::string& token) {
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST0(
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "identity", "GaiaWebAuthFlow", this, "OnUbertokenSuccess");
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kMergeSessionQueryFormat[] = "?uberauth=%s&"
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                          "continue=%s&"
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                          "source=appsv2";
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string merge_query = base::StringPrintf(
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      kMergeSessionQueryFormat,
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      net::EscapeUrlEncodedData(token, true).c_str(),
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      net::EscapeUrlEncodedData(auth_url_.spec(), true).c_str());
113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  GURL merge_url(
114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      GaiaUrls::GetInstance()->merge_session_url().Resolve(merge_query));
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  web_flow_ = CreateWebAuthFlow(merge_url);
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  web_flow_->Start();
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GaiaWebAuthFlow::OnUbertokenFailure(const GoogleServiceAuthError& error) {
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST1("identity",
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "GaiaWebAuthFlow",
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnUbertokenSuccess",
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "error",
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               error.ToString());
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
12846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DVLOG(1) << "OnUbertokenFailure: " << error.error_message();
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  delegate_->OnGaiaFlowFailure(
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GaiaWebAuthFlow::SERVICE_AUTH_ERROR, error, std::string());
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GaiaWebAuthFlow::OnAuthFlowFailure(WebAuthFlow::Failure failure) {
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  GaiaWebAuthFlow::Failure gaia_failure;
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  switch (failure) {
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case WebAuthFlow::WINDOW_CLOSED:
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      gaia_failure = GaiaWebAuthFlow::WINDOW_CLOSED;
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case WebAuthFlow::LOAD_FAILED:
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      DVLOG(1) << "OnAuthFlowFailure LOAD_FAILED";
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      gaia_failure = GaiaWebAuthFlow::LOAD_FAILED;
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    default:
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      NOTREACHED() << "Unexpected error from web auth flow: " << failure;
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      gaia_failure = GaiaWebAuthFlow::LOAD_FAILED;
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST1("identity",
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "GaiaWebAuthFlow",
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnAuthFlowFailure",
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "error",
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               gaia_failure);
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  delegate_->OnGaiaFlowFailure(
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      gaia_failure,
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GoogleServiceAuthError(GoogleServiceAuthError::NONE),
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::string());
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GaiaWebAuthFlow::OnAuthFlowURLChange(const GURL& url) {
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_STEP_PAST0("identity",
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "GaiaWebAuthFlow",
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               this,
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               "OnAuthFlowURLChange");
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kOAuth2RedirectAccessTokenKey[] = "access_token";
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kOAuth2RedirectErrorKey[] = "error";
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kOAuth2ExpiresInKey[] = "expires_in";
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The format of the target URL is:
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //     reversed.oauth.client.id:/extensionid#access_token=TOKEN
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Because there is no double slash, everything after the scheme is
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // interpreted as a path, including the fragment.
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (url.scheme() == redirect_scheme_ && !url.has_host() && !url.has_port() &&
1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      StartsWithASCII(url.GetContent(), redirect_path_prefix_, true)) {
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    web_flow_.release()->DetachDelegateAndDelete();
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    std::string fragment = url.GetContent().substr(
1841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        redirect_path_prefix_.length(), std::string::npos);
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::StringPairs pairs;
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::SplitStringIntoKeyValuePairs(fragment, '=', '&', &pairs);
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string access_token;
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string error;
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string expiration;
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for (base::StringPairs::iterator it = pairs.begin();
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         it != pairs.end();
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)         ++it) {
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (it->first == kOAuth2RedirectAccessTokenKey)
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        access_token = it->second;
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      else if (it->first == kOAuth2RedirectErrorKey)
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        error = it->second;
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      else if (it->first == kOAuth2ExpiresInKey)
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        expiration = it->second;
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (access_token.empty() && error.empty()) {
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      delegate_->OnGaiaFlowFailure(
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          GaiaWebAuthFlow::INVALID_REDIRECT,
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          GoogleServiceAuthError(GoogleServiceAuthError::NONE),
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          std::string());
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else if (!error.empty()) {
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      delegate_->OnGaiaFlowFailure(
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          GaiaWebAuthFlow::OAUTH_ERROR,
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          GoogleServiceAuthError(GoogleServiceAuthError::NONE),
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          error);
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      delegate_->OnGaiaFlowCompleted(access_token, expiration);
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GaiaWebAuthFlow::OnAuthFlowTitleChange(const std::string& title) {
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // On the final page the title will be "Loading <redirect-url>".
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Treat it as though we'd really been redirected to <redirect-url>.
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char kRedirectPrefix[] = "Loading ";
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string prefix(kRedirectPrefix);
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (StartsWithASCII(title, prefix, true)) {
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GURL url(title.substr(prefix.length(), std::string::npos));
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (url.is_valid())
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      OnAuthFlowURLChange(url);
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)scoped_ptr<WebAuthFlow> GaiaWebAuthFlow::CreateWebAuthFlow(GURL url) {
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return scoped_ptr<WebAuthFlow>(new WebAuthFlow(this,
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                 profile_,
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                 url,
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                                 WebAuthFlow::INTERACTIVE));
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
238d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}  // namespace extensions
239