Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h" | |
| 6 | |
| 7 #include "base/string_util.h" | |
| 8 #include "base/stringprintf.h" | |
| 9 #include "base/strings/string_number_conversions.h" | |
| 10 #include "base/strings/string_split.h" | |
| 11 #include "google_apis/gaia/gaia_urls.h" | |
| 12 #include "net/base/escape.h" | |
| 13 | |
| 14 namespace extensions { | |
| 15 | |
| 16 GaiaWebAuthFlow::GaiaWebAuthFlow(Delegate* delegate, | |
| 17 Profile* profile, | |
| 18 chrome::HostDesktopType host_desktop_type, | |
| 19 const std::string& extension_id, | |
| 20 const OAuth2Info& oauth2_info) | |
| 21 : delegate_(delegate), | |
| 22 profile_(profile), | |
| 23 host_desktop_type_(host_desktop_type) { | |
| 24 const char kOAuth2RedirectPathFormat[] = "/%s#"; | |
| 25 const char kOAuth2AuthorizeFormat[] = | |
| 26 "%s?response_type=token&approval_prompt=force&authuser=0&" | |
| 27 "client_id=%s&" | |
| 28 "scope=%s&" | |
| 29 "origin=chrome-extension://%s/&" | |
| 30 "redirect_uri=%s:/%s"; | |
| 31 | |
| 32 std::vector<std::string> client_id_parts; | |
| 33 base::SplitString(oauth2_info.client_id, '.', &client_id_parts); | |
| 34 std::reverse(client_id_parts.begin(), client_id_parts.end()); | |
| 35 redirect_scheme_ = JoinString(client_id_parts, '.'); | |
| 36 | |
| 37 redirect_path_prefix_ = | |
| 38 base::StringPrintf(kOAuth2RedirectPathFormat, extension_id.c_str()); | |
| 39 | |
| 40 auth_url_ = base::StringPrintf( | |
| 41 kOAuth2AuthorizeFormat, | |
| 42 GaiaUrls::GetInstance()->oauth2_auth_url().c_str(), | |
| 43 oauth2_info.client_id.c_str(), | |
| 44 net::EscapeUrlEncodedData(JoinString(oauth2_info.scopes, ' '), true) | |
| 45 .c_str(), | |
| 46 extension_id.c_str(), | |
| 47 redirect_scheme_.c_str(), | |
| 48 extension_id.c_str()); | |
| 49 } | |
| 50 | |
| 51 GaiaWebAuthFlow::~GaiaWebAuthFlow() {} | |
| 52 | |
| 53 void GaiaWebAuthFlow::Start() { | |
| 54 ubertoken_fetcher_.reset(new UbertokenFetcher(profile_, this)); | |
| 55 ubertoken_fetcher_->StartFetchingToken(); | |
| 56 } | |
| 57 | |
| 58 void GaiaWebAuthFlow::OnUbertokenSuccess(const std::string& token) { | |
| 59 const char kMergeSessionQueryFormat[] = "?uberauth=%s&" | |
| 60 "continue=%s&" | |
| 61 "source=appsv2"; | |
| 62 | |
| 63 std::string merge_query = | |
| 64 base::StringPrintf(kMergeSessionQueryFormat, | |
| 65 net::EscapeUrlEncodedData(token, true).c_str(), | |
| 66 net::EscapeUrlEncodedData(auth_url_, true).c_str()); | |
| 67 GURL merge_url(GaiaUrls::GetInstance()->merge_session_url() + merge_query); | |
| 68 | |
| 69 web_flow_ = CreateWebAuthFlow(merge_url); | |
| 70 web_flow_->Start(); | |
| 71 } | |
| 72 | |
| 73 void GaiaWebAuthFlow::OnUbertokenFailure(const GoogleServiceAuthError& error) { | |
| 74 delegate_->OnGaiaFlowFailure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR, error); | |
| 75 } | |
| 76 | |
| 77 void GaiaWebAuthFlow::OnAuthFlowFailure(WebAuthFlow::Failure failure) { | |
| 78 DCHECK(failure == WebAuthFlow::WINDOW_CLOSED); | |
| 79 delegate_->OnGaiaFlowFailure( | |
| 80 GaiaWebAuthFlow::WINDOW_CLOSED, | |
| 81 GoogleServiceAuthError(GoogleServiceAuthError::NONE)); | |
| 82 } | |
| 83 | |
| 84 void GaiaWebAuthFlow::OnAuthFlowURLChange(const GURL& url) { | |
| 85 const char kOAuth2RedirectAccessTokenKey[] = "access_token="; | |
| 86 const char kOAuth2RedirectErrorKey[] = "error="; | |
| 87 const char kOAuth2ExpiresInKey[] = "expires_in="; | |
| 88 | |
| 89 // The format of the target URL is: | |
| 90 // reversed.oauth.client.id:/extensionid#access_token=TOKEN | |
| 91 // | |
| 92 // Because there is no double slash, everything after the scheme is | |
| 93 // interpreted as a path, including the fragment. | |
| 94 | |
| 95 if (url.scheme() == redirect_scheme_ && !url.has_host() && !url.has_port() && | |
| 96 StartsWithASCII(url.path(), redirect_path_prefix_, true)) { | |
| 97 web_flow_.reset(); | |
| 98 | |
| 99 std::string fragment = | |
| 100 url.path().substr(redirect_path_prefix_.length(), std::string::npos); | |
| 101 std::vector<std::string> parts; | |
| 102 base::SplitString(fragment, '&', &parts); | |
| 103 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!
| |
| 104 std::string error_key(kOAuth2RedirectErrorKey); | |
| 105 std::string expiration_key(kOAuth2ExpiresInKey); | |
| 106 std::string access_token; | |
| 107 std::string error; | |
| 108 std::string expiration; | |
| 109 | |
| 110 for (std::vector<std::string>::iterator it = parts.begin(); | |
| 111 it != parts.end(); | |
| 112 ++it) { | |
| 113 if (StartsWithASCII(*it, token_key, true)) | |
| 114 access_token = it->substr(token_key.length(), std::string::npos); | |
| 115 else if (StartsWithASCII(*it, error_key, true)) | |
| 116 error = it->substr(error_key.length(), std::string::npos); | |
| 117 else if (StartsWithASCII(*it, expiration_key, true)) | |
| 118 expiration = it->substr(expiration_key.length(), std::string::npos); | |
| 119 } | |
| 120 | |
| 121 if (access_token.empty() && error.empty()) { | |
| 122 delegate_->OnGaiaFlowFailure( | |
| 123 GaiaWebAuthFlow::INVALID_REDIRECT, | |
| 124 GoogleServiceAuthError(GoogleServiceAuthError::NONE)); | |
| 125 } else { | |
| 126 delegate_->OnGaiaFlowCompleted(access_token, expiration, error); | |
| 127 } | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 void GaiaWebAuthFlow::OnAuthFlowTitleChange(const std::string& title) { | |
| 132 // On the final page the title will be "Loading <redirect-url>". | |
| 133 // Treat it as though we'd really been redirected to <redirect-url>. | |
| 134 const char kRedirectPrefix[] = "Loading "; | |
| 135 std::string prefix(kRedirectPrefix); | |
| 136 | |
| 137 if (StartsWithASCII(title, prefix, true)) { | |
| 138 GURL url(title.substr(prefix.length(), std::string::npos)); | |
| 139 if (url.is_valid()) | |
| 140 OnAuthFlowURLChange(url); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 scoped_ptr<WebAuthFlow> GaiaWebAuthFlow::CreateWebAuthFlow(GURL url) { | |
| 145 gfx::Rect initial_bounds; | |
| 146 return scoped_ptr<WebAuthFlow>(new WebAuthFlow(this, | |
| 147 profile_, | |
| 148 url, | |
| 149 WebAuthFlow::INTERACTIVE, | |
| 150 initial_bounds, | |
| 151 host_desktop_type_)); | |
| 152 } | |
| 153 | |
| 154 } // extensions | |
| OLD | NEW |