Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1379)

Unified Diff: chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc

Issue 15148007: Identity API: web-based scope approval dialogs for getAuthToken (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: better protocol description Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698