Chromium Code Reviews| 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..2e1b702203b0f7167b0800e1f9fe223aec87ef5c |
| --- /dev/null |
| +++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc |
| @@ -0,0 +1,154 @@ |
| +// 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_ = 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_, 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); |
| +} |
| + |
| +void GaiaWebAuthFlow::OnAuthFlowFailure(WebAuthFlow::Failure failure) { |
| + DCHECK(failure == WebAuthFlow::WINDOW_CLOSED); |
| + delegate_->OnGaiaFlowFailure( |
| + GaiaWebAuthFlow::WINDOW_CLOSED, |
| + GoogleServiceAuthError(GoogleServiceAuthError::NONE)); |
| +} |
| + |
| +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::string> parts; |
| + base::SplitString(fragment, '&', &parts); |
| + std::string token_key(kOAuth2RedirectAccessTokenKey); |
|
Roger Tawa OOO till Jul 10th
2013/05/16 16:06:15
Better to use:
std::vector<std::pair<std::strin
Michael Courage
2013/05/16 20:39:02
Done. That's so much nicer, thanks!
|
| + std::string error_key(kOAuth2RedirectErrorKey); |
| + std::string expiration_key(kOAuth2ExpiresInKey); |
| + std::string access_token; |
| + std::string error; |
| + std::string expiration; |
| + |
| + for (std::vector<std::string>::iterator it = parts.begin(); |
| + it != parts.end(); |
| + ++it) { |
| + if (StartsWithASCII(*it, token_key, true)) |
| + access_token = it->substr(token_key.length(), std::string::npos); |
| + else if (StartsWithASCII(*it, error_key, true)) |
| + error = it->substr(error_key.length(), std::string::npos); |
| + else if (StartsWithASCII(*it, expiration_key, true)) |
| + expiration = it->substr(expiration_key.length(), std::string::npos); |
| + } |
| + |
| + if (access_token.empty() && error.empty()) { |
| + delegate_->OnGaiaFlowFailure( |
| + GaiaWebAuthFlow::INVALID_REDIRECT, |
| + GoogleServiceAuthError(GoogleServiceAuthError::NONE)); |
| + } else { |
| + delegate_->OnGaiaFlowCompleted(access_token, expiration, error); |
| + } |
| + } |
| +} |
| + |
| +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 |