| Index: chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
|
| diff --git a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9362b3bbc2d3f55bbfaaeae0cc65b0b5121cade7
|
| --- /dev/null
|
| +++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
|
| @@ -0,0 +1,160 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h"
|
| +
|
| +#include "base/string_util.h"
|
| +#include "base/stringprintf.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "google_apis/gaia/gaia_urls.h"
|
| +#include "net/base/escape.h"
|
| +
|
| +namespace extensions {
|
| +
|
| +GaiaWebAuthFlow::GaiaWebAuthFlow(Delegate* delegate,
|
| + Profile* profile,
|
| + chrome::HostDesktopType host_desktop_type,
|
| + const std::string& extension_id,
|
| + const OAuth2Info& oauth2_info)
|
| + : delegate_(delegate),
|
| + profile_(profile),
|
| + host_desktop_type_(host_desktop_type) {
|
| + const char kOAuth2RedirectPathFormat[] = "/%s#";
|
| + const char kOAuth2AuthorizeFormat[] =
|
| + "%s?response_type=token&approval_prompt=force&authuser=0&"
|
| + "client_id=%s&"
|
| + "scope=%s&"
|
| + "origin=chrome-extension://%s/&"
|
| + "redirect_uri=%s:/%s";
|
| +
|
| + std::vector<std::string> client_id_parts;
|
| + base::SplitString(oauth2_info.client_id, '.', &client_id_parts);
|
| + std::reverse(client_id_parts.begin(), client_id_parts.end());
|
| + redirect_scheme_ = JoinString(client_id_parts, '.');
|
| +
|
| + redirect_path_prefix_ =
|
| + base::StringPrintf(kOAuth2RedirectPathFormat, extension_id.c_str());
|
| +
|
| + auth_url_ = GURL(base::StringPrintf(
|
| + kOAuth2AuthorizeFormat,
|
| + GaiaUrls::GetInstance()->oauth2_auth_url().c_str(),
|
| + oauth2_info.client_id.c_str(),
|
| + net::EscapeUrlEncodedData(JoinString(oauth2_info.scopes, ' '), true)
|
| + .c_str(),
|
| + extension_id.c_str(),
|
| + redirect_scheme_.c_str(),
|
| + extension_id.c_str()));
|
| +}
|
| +
|
| +GaiaWebAuthFlow::~GaiaWebAuthFlow() {}
|
| +
|
| +void GaiaWebAuthFlow::Start() {
|
| + ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this));
|
| + ubertoken_fetcher_->StartFetchingToken();
|
| +}
|
| +
|
| +void GaiaWebAuthFlow::OnUbertokenSuccess(const std::string& token) {
|
| + const char kMergeSessionQueryFormat[] = "?uberauth=%s&"
|
| + "continue=%s&"
|
| + "source=appsv2";
|
| +
|
| + std::string merge_query = base::StringPrintf(
|
| + kMergeSessionQueryFormat,
|
| + net::EscapeUrlEncodedData(token, true).c_str(),
|
| + net::EscapeUrlEncodedData(auth_url_.spec(), true).c_str());
|
| + GURL merge_url(GaiaUrls::GetInstance()->merge_session_url() + merge_query);
|
| +
|
| + web_flow_ = CreateWebAuthFlow(merge_url);
|
| + web_flow_->Start();
|
| +}
|
| +
|
| +void GaiaWebAuthFlow::OnUbertokenFailure(const GoogleServiceAuthError& error) {
|
| + delegate_->OnGaiaFlowFailure(
|
| + GaiaWebAuthFlow::SERVICE_AUTH_ERROR, error, std::string());
|
| +}
|
| +
|
| +void GaiaWebAuthFlow::OnAuthFlowFailure(WebAuthFlow::Failure failure) {
|
| + DCHECK(failure == WebAuthFlow::WINDOW_CLOSED);
|
| + delegate_->OnGaiaFlowFailure(
|
| + GaiaWebAuthFlow::WINDOW_CLOSED,
|
| + GoogleServiceAuthError(GoogleServiceAuthError::NONE),
|
| + std::string());
|
| +}
|
| +
|
| +void GaiaWebAuthFlow::OnAuthFlowURLChange(const GURL& url) {
|
| + const char kOAuth2RedirectAccessTokenKey[] = "access_token";
|
| + const char kOAuth2RedirectErrorKey[] = "error";
|
| + const char kOAuth2ExpiresInKey[] = "expires_in";
|
| +
|
| + // The format of the target URL is:
|
| + // reversed.oauth.client.id:/extensionid#access_token=TOKEN
|
| + //
|
| + // Because there is no double slash, everything after the scheme is
|
| + // interpreted as a path, including the fragment.
|
| +
|
| + if (url.scheme() == redirect_scheme_ && !url.has_host() && !url.has_port() &&
|
| + StartsWithASCII(url.path(), redirect_path_prefix_, true)) {
|
| + web_flow_.reset();
|
| +
|
| + std::string fragment =
|
| + url.path().substr(redirect_path_prefix_.length(), std::string::npos);
|
| + std::vector<std::pair<std::string, std::string> > pairs;
|
| + base::SplitStringIntoKeyValuePairs(fragment, '=', '&', &pairs);
|
| + std::string access_token;
|
| + std::string error;
|
| + std::string expiration;
|
| +
|
| + for (std::vector<std::pair<std::string, std::string> >::iterator
|
| + it = pairs.begin();
|
| + it != pairs.end();
|
| + ++it) {
|
| + if (it->first == kOAuth2RedirectAccessTokenKey)
|
| + access_token = it->second;
|
| + else if (it->first == kOAuth2RedirectErrorKey)
|
| + error = it->second;
|
| + else if (it->first == kOAuth2ExpiresInKey)
|
| + expiration = it->second;
|
| + }
|
| +
|
| + if (access_token.empty() && error.empty()) {
|
| + delegate_->OnGaiaFlowFailure(
|
| + GaiaWebAuthFlow::INVALID_REDIRECT,
|
| + GoogleServiceAuthError(GoogleServiceAuthError::NONE),
|
| + std::string());
|
| + } else if (!error.empty()) {
|
| + delegate_->OnGaiaFlowFailure(
|
| + GaiaWebAuthFlow::OAUTH_ERROR,
|
| + GoogleServiceAuthError(GoogleServiceAuthError::NONE),
|
| + error);
|
| + } else {
|
| + delegate_->OnGaiaFlowCompleted(access_token, expiration);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void GaiaWebAuthFlow::OnAuthFlowTitleChange(const std::string& title) {
|
| + // On the final page the title will be "Loading <redirect-url>".
|
| + // Treat it as though we'd really been redirected to <redirect-url>.
|
| + const char kRedirectPrefix[] = "Loading ";
|
| + std::string prefix(kRedirectPrefix);
|
| +
|
| + if (StartsWithASCII(title, prefix, true)) {
|
| + GURL url(title.substr(prefix.length(), std::string::npos));
|
| + if (url.is_valid())
|
| + OnAuthFlowURLChange(url);
|
| + }
|
| +}
|
| +
|
| +scoped_ptr<WebAuthFlow> GaiaWebAuthFlow::CreateWebAuthFlow(GURL url) {
|
| + gfx::Rect initial_bounds;
|
| + return scoped_ptr<WebAuthFlow>(new WebAuthFlow(this,
|
| + profile_,
|
| + url,
|
| + WebAuthFlow::INTERACTIVE,
|
| + initial_bounds,
|
| + host_desktop_type_));
|
| +}
|
| +
|
| +} // extensions
|
|
|