summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorjamiewalch@google.com <jamiewalch@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-16 21:53:51 +0000
committerjamiewalch@google.com <jamiewalch@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-16 21:53:51 +0000
commit53021f822333a6e12a552b37a0e82b41bc85c867 (patch)
tree38278a89a6c379b286c8077ac40e4951796736d1 /remoting
parent90f53ef834d187fe71d4deb102c822475295aa8a (diff)
downloadchromium_src-53021f822333a6e12a552b37a0e82b41bc85c867.zip
chromium_src-53021f822333a6e12a552b37a0e82b41bc85c867.tar.gz
chromium_src-53021f822333a6e12a552b37a0e82b41bc85c867.tar.bz2
Added helper classes to allow OAuth to be used in Me2Me.
These classes are heavily based on equivalents under chrome/service, although they're somewhat simpler. This is part of the groundwork needed to let us use OAuth instead of Client Login for Me2Me. The web-app can present a refresh token, and these classes will allow us to turn it into an access token on-demand. BUG=None TEST=None Review URL: https://chromiumcodereview.appspot.com/9677027 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127260 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/host/DEPS5
-rw-r--r--remoting/host/gaia_oauth_client.cc207
-rw-r--r--remoting/host/gaia_oauth_client.h78
-rw-r--r--remoting/host/oauth_client.cc44
-rw-r--r--remoting/host/oauth_client.h40
-rw-r--r--remoting/host/url_request_context.cc73
-rw-r--r--remoting/host/url_request_context.h53
-rw-r--r--remoting/remoting.gyp7
8 files changed, 507 insertions, 0 deletions
diff --git a/remoting/host/DEPS b/remoting/host/DEPS
index bc54a47..c84c993 100644
--- a/remoting/host/DEPS
+++ b/remoting/host/DEPS
@@ -1,7 +1,12 @@
include_rules = [
"+ui",
"+base/crypto",
+ "+content/public/common",
"+net/base",
+ "+net/ftp",
+ "+net/http",
+ "+net/proxy",
+ "+net/url_request",
"+remoting/protocol",
"+remoting/jingle_glue",
diff --git a/remoting/host/gaia_oauth_client.cc b/remoting/host/gaia_oauth_client.cc
new file mode 100644
index 0000000..8b2844b
--- /dev/null
+++ b/remoting/host/gaia_oauth_client.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 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 "remoting/host/gaia_oauth_client.h"
+
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "content/public/common/url_fetcher.h"
+#include "content/public/common/url_fetcher_delegate.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/escape.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace {
+const char kAccessTokenValue[] = "access_token";
+const char kRefreshTokenValue[] = "refresh_token";
+const char kExpiresInValue[] = "expires_in";
+} // namespace
+
+namespace remoting {
+
+class GaiaOAuthClient::Core
+ : public base::RefCountedThreadSafe<GaiaOAuthClient::Core>,
+ public content::URLFetcherDelegate {
+ public:
+ Core(const std::string& gaia_url,
+ net::URLRequestContextGetter* request_context_getter)
+ : gaia_url_(gaia_url),
+ num_retries_(0),
+ request_context_getter_(request_context_getter),
+ delegate_(NULL) { }
+
+ virtual ~Core() { }
+
+ void GetTokensFromAuthCode(const OAuthClientInfo& oauth_client_info,
+ const std::string& auth_code,
+ int max_retries,
+ GaiaOAuthClient::Delegate* delegate);
+ void RefreshToken(const OAuthClientInfo& oauth_client_info,
+ const std::string& refresh_token,
+ int max_retries,
+ GaiaOAuthClient::Delegate* delegate);
+
+ // content::URLFetcherDelegate implementation.
+ virtual void OnURLFetchComplete(const content::URLFetcher* source);
+
+ private:
+ void MakeGaiaRequest(std::string post_body,
+ int max_retries,
+ GaiaOAuthClient::Delegate* delegate);
+ void HandleResponse(const content::URLFetcher* source,
+ bool* should_retry_request);
+
+ GURL gaia_url_;
+ int num_retries_;
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ GaiaOAuthClient::Delegate* delegate_;
+ scoped_ptr<content::URLFetcher> request_;
+};
+
+void GaiaOAuthClient::Core::GetTokensFromAuthCode(
+ const OAuthClientInfo& oauth_client_info,
+ const std::string& auth_code,
+ int max_retries,
+ GaiaOAuthClient::Delegate* delegate) {
+ std::string post_body =
+ "code=" + net::EscapeUrlEncodedData(auth_code, true) +
+ "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id,
+ true) +
+ "&client_secret=" +
+ net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) +
+ "&redirect_uri=oob&grant_type=authorization_code";
+ MakeGaiaRequest(post_body, max_retries, delegate);
+}
+
+void GaiaOAuthClient::Core::RefreshToken(
+ const OAuthClientInfo& oauth_client_info,
+ const std::string& refresh_token,
+ int max_retries,
+ GaiaOAuthClient::Delegate* delegate) {
+ std::string post_body =
+ "refresh_token=" + net::EscapeUrlEncodedData(refresh_token, true) +
+ "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id,
+ true) +
+ "&client_secret=" +
+ net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) +
+ "&grant_type=refresh_token";
+ MakeGaiaRequest(post_body, max_retries, delegate);
+}
+
+void GaiaOAuthClient::Core::MakeGaiaRequest(
+ std::string post_body,
+ int max_retries,
+ GaiaOAuthClient::Delegate* delegate) {
+ DCHECK(!request_.get()) << "Tried to fetch two things at once!";
+ delegate_ = delegate;
+ num_retries_ = 0;
+ request_.reset(content::URLFetcher::Create(
+ 0, gaia_url_, content::URLFetcher::POST, this));
+ request_->SetRequestContext(request_context_getter_);
+ request_->SetUploadData("application/x-www-form-urlencoded", post_body);
+ request_->SetMaxRetries(max_retries);
+ request_->Start();
+}
+
+// URLFetcher::Delegate implementation.
+void GaiaOAuthClient::Core::OnURLFetchComplete(
+ const content::URLFetcher* source) {
+ bool should_retry = false;
+ HandleResponse(source, &should_retry);
+ if (should_retry) {
+ // Explicitly call ReceivedContentWasMalformed() to ensure the current
+ // request gets counted as a failure for calculation of the back-off
+ // period. If it was already a failure by status code, this call will
+ // be ignored.
+ request_->ReceivedContentWasMalformed();
+ num_retries_++;
+ // We must set our request_context_getter_ again because
+ // URLFetcher::Core::RetryOrCompleteUrlFetch resets it to NULL...
+ request_->SetRequestContext(request_context_getter_);
+ request_->Start();
+ } else {
+ request_.reset();
+ }
+}
+
+void GaiaOAuthClient::Core::HandleResponse(
+ const content::URLFetcher* source,
+ bool* should_retry_request) {
+ *should_retry_request = false;
+ // RC_BAD_REQUEST means the arguments are invalid. No point retrying. We are
+ // done here.
+ if (source->GetResponseCode() == net::HTTP_BAD_REQUEST) {
+ delegate_->OnOAuthError();
+ return;
+ }
+ std::string access_token;
+ std::string refresh_token;
+ int expires_in_seconds = 0;
+ if (source->GetResponseCode() == net::HTTP_OK) {
+ std::string data;
+ source->GetResponseAsString(&data);
+ scoped_ptr<Value> message_value(base::JSONReader::Read(data, false));
+ if (message_value.get() &&
+ message_value->IsType(Value::TYPE_DICTIONARY)) {
+ scoped_ptr<DictionaryValue> response_dict(
+ static_cast<DictionaryValue*>(message_value.release()));
+ response_dict->GetString(kAccessTokenValue, &access_token);
+ response_dict->GetString(kRefreshTokenValue, &refresh_token);
+ response_dict->GetInteger(kExpiresInValue, &expires_in_seconds);
+ }
+ }
+ if (access_token.empty()) {
+ // If we don't have an access token yet and the the error was not
+ // RC_BAD_REQUEST, we may need to retry.
+ if ((-1 != source->GetMaxRetries()) &&
+ (num_retries_ > source->GetMaxRetries())) {
+ // Retry limit reached. Give up.
+ delegate_->OnNetworkError(source->GetResponseCode());
+ } else {
+ *should_retry_request = true;
+ }
+ } else if (refresh_token.empty()) {
+ // If we only have an access token, then this was a refresh request.
+ delegate_->OnRefreshTokenResponse(access_token, expires_in_seconds);
+ } else {
+ delegate_->OnGetTokensResponse(refresh_token,
+ access_token,
+ expires_in_seconds);
+ }
+}
+
+GaiaOAuthClient::GaiaOAuthClient(const std::string& gaia_url,
+ net::URLRequestContextGetter* context_getter) {
+ core_ = new Core(gaia_url, context_getter);
+}
+
+GaiaOAuthClient::~GaiaOAuthClient() {
+}
+
+
+void GaiaOAuthClient::GetTokensFromAuthCode(
+ const OAuthClientInfo& oauth_client_info,
+ const std::string& auth_code,
+ int max_retries,
+ Delegate* delegate) {
+ return core_->GetTokensFromAuthCode(oauth_client_info,
+ auth_code,
+ max_retries,
+ delegate);
+}
+
+void GaiaOAuthClient::RefreshToken(const OAuthClientInfo& oauth_client_info,
+ const std::string& refresh_token,
+ int max_retries,
+ Delegate* delegate) {
+ return core_->RefreshToken(oauth_client_info,
+ refresh_token,
+ max_retries,
+ delegate);
+}
+
+} // namespace remoting
diff --git a/remoting/host/gaia_oauth_client.h b/remoting/host/gaia_oauth_client.h
new file mode 100644
index 0000000..f893037
--- /dev/null
+++ b/remoting/host/gaia_oauth_client.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 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.
+
+#ifndef REMOTING_HOST_GAIA_OAUTH_CLIENT_H_
+#define REMOTING_HOST_GAIA_OAUTH_CLIENT_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/message_loop_proxy.h"
+
+namespace net {
+class URLRequestContextGetter;
+} // namespace net
+
+// A helper class to get and refresh OAuth tokens given an authorization code.
+//
+// TODO(jamiewalch): This is copied from chrome/common/net to avoid a dependency
+// on chrome. It would be better for this class to be moved into net to avoid
+// this duplication.
+namespace remoting {
+
+// TODO(jamiewalch): Make this configurable if we ever support other providers.
+static const char kGaiaOAuth2Url[] =
+ "https://accounts.google.com/o/oauth2/token";
+
+struct OAuthClientInfo {
+ std::string client_id;
+ std::string client_secret;
+};
+
+class GaiaOAuthClient {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() { }
+
+ // Invoked on a successful response to the GetTokensFromAuthCode request.
+ virtual void OnGetTokensResponse(const std::string& refresh_token,
+ const std::string& access_token,
+ int expires_in_seconds) = 0;
+ // Invoked on a successful response to the RefreshToken request.
+ virtual void OnRefreshTokenResponse(const std::string& access_token,
+ int expires_in_seconds) = 0;
+ // Invoked when there is an OAuth error with one of the requests.
+ virtual void OnOAuthError() = 0;
+ // Invoked when there is a network error or upon receiving an invalid
+ // response. This is invoked when the maximum number of retries have been
+ // exhausted. If max_retries is -1, this is never invoked.
+ virtual void OnNetworkError(int response_code) = 0;
+ };
+ GaiaOAuthClient(const std::string& gaia_url,
+ net::URLRequestContextGetter* context_getter);
+ ~GaiaOAuthClient();
+
+ // In the below methods, |max_retries| specifies the maximum number of times
+ // we should retry on a network error in invalid response. This does not
+ // apply in the case of an OAuth error (i.e. there was something wrong with
+ // the input arguments). Setting |max_retries| to -1 implies infinite retries.
+ void GetTokensFromAuthCode(const OAuthClientInfo& oauth_client_info,
+ const std::string& auth_code,
+ int max_retries,
+ Delegate* delegate);
+ void RefreshToken(const OAuthClientInfo& oauth_client_info,
+ const std::string& refresh_token,
+ int max_retries,
+ Delegate* delegate);
+
+ private:
+ // The guts of the implementation live in this class.
+ class Core;
+ scoped_refptr<Core> core_;
+ DISALLOW_COPY_AND_ASSIGN(GaiaOAuthClient);
+};
+} // namespace remoting
+
+#endif // CHROME_COMMON_NET_GAIA_GAIA_OAUTH_CLIENT_H_
diff --git a/remoting/host/oauth_client.cc b/remoting/host/oauth_client.cc
new file mode 100644
index 0000000..342b0eb
--- /dev/null
+++ b/remoting/host/oauth_client.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 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 "remoting/host/oauth_client.h"
+
+#include "remoting/host/chromoting_host_context.h"
+#include "remoting/host/url_request_context.h"
+
+namespace remoting {
+
+OAuthClient::OAuthClient()
+ : network_thread_("OAuthNetworkThread"),
+ file_thread_("OAuthFileThread") {
+ network_thread_.StartWithOptions(
+ base::Thread::Options(MessageLoop::TYPE_IO, 0));
+ file_thread_.StartWithOptions(
+ base::Thread::Options(MessageLoop::TYPE_IO, 0));
+ url_request_context_getter_.reset(new URLRequestContextGetter(
+ network_thread_.message_loop(), file_thread_.message_loop()));
+ gaia_oauth_client_.reset(
+ new GaiaOAuthClient(kGaiaOAuth2Url, url_request_context_getter_.get()));
+}
+
+OAuthClient::~OAuthClient() {
+}
+
+void OAuthClient::GetAccessToken(const std::string& refresh_token,
+ GaiaOAuthClient::Delegate* delegate) {
+#ifdef OFFICIAL_BUILD
+ OAuthClientInfo client_info = {
+ "440925447803-avn2sj1kc099s0r7v62je5s339mu0am1.apps.googleusercontent.com",
+ "Bgur6DFiOMM1h8x-AQpuTQlK"
+ };
+#else
+ OAuthClientInfo client_info = {
+ "440925447803-2pi3v45bff6tp1rde2f7q6lgbor3o5uj.apps.googleusercontent.com",
+ "W2ieEsG-R1gIA4MMurGrgMc_"
+ };
+#endif
+ gaia_oauth_client_->RefreshToken(client_info, refresh_token, -1, delegate);
+}
+
+} // namespace remoting
diff --git a/remoting/host/oauth_client.h b/remoting/host/oauth_client.h
new file mode 100644
index 0000000..c377733
--- /dev/null
+++ b/remoting/host/oauth_client.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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.
+//
+// This class implements the OAuth2 client for the Chromoting host.
+
+#ifndef REMOTING_HOST_OAUTH_CLIENT_H_
+#define REMOTING_HOST_OAUTH_CLIENT_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread.h"
+#include "remoting/host/gaia_oauth_client.h"
+#include "remoting/host/url_request_context.h"
+
+namespace remoting {
+
+class OAuthClient {
+ public:
+ OAuthClient();
+ ~OAuthClient();
+
+ void GetAccessToken(const std::string& refresh_token,
+ GaiaOAuthClient::Delegate* delegate);
+
+ private:
+ // TODO(jamiewalch): Move these to the ChromotingHostContext class so
+ // that the URLRequestContextGetter is available for other purposes.
+ base::Thread network_thread_;
+ base::Thread file_thread_;
+ scoped_ptr<URLRequestContextGetter> url_request_context_getter_;
+ scoped_ptr<GaiaOAuthClient> gaia_oauth_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(OAuthClient);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_OAUTH_CLIENT_H_
diff --git a/remoting/host/url_request_context.cc b/remoting/host/url_request_context.cc
new file mode 100644
index 0000000..4ba46ff
--- /dev/null
+++ b/remoting/host/url_request_context.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 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 "remoting/host/url_request_context.h"
+
+#include "base/message_loop_proxy.h"
+#include "net/base/cert_verifier.h"
+#include "net/base/host_resolver.h"
+#include "net/base/ssl_config_service_defaults.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_network_layer.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/proxy/proxy_config_service.h"
+#include "net/proxy/proxy_service.h"
+
+namespace remoting {
+
+// TODO(willchan): This is largely copied from service_url_request_context.cc,
+// which is in turn copied from some test code. Move it somewhere reusable.
+URLRequestContext::URLRequestContext(
+ net::ProxyConfigService* proxy_config_service)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(storage_(this)) {
+ storage_.set_host_resolver(
+ net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
+ net::HostResolver::kDefaultRetryAttempts,
+ NULL));
+ storage_.set_proxy_service(net::ProxyService::CreateUsingSystemProxyResolver(
+ proxy_config_service, 0u, NULL));
+ storage_.set_cert_verifier(new net::CertVerifier);
+ storage_.set_ssl_config_service(new net::SSLConfigServiceDefaults);
+ storage_.set_http_auth_handler_factory(
+ net::HttpAuthHandlerFactory::CreateDefault(host_resolver()));
+ storage_.set_http_server_properties(new net::HttpServerPropertiesImpl);
+
+ net::HttpNetworkSession::Params session_params;
+ session_params.host_resolver = host_resolver();
+ session_params.cert_verifier = cert_verifier();
+ session_params.proxy_service = proxy_service();
+ session_params.ssl_config_service = ssl_config_service();
+ session_params.http_auth_handler_factory = http_auth_handler_factory();
+ session_params.http_server_properties = http_server_properties();
+ scoped_refptr<net::HttpNetworkSession> network_session(
+ new net::HttpNetworkSession(session_params));
+ storage_.set_http_transaction_factory(
+ new net::HttpNetworkLayer(network_session));
+}
+
+URLRequestContextGetter::URLRequestContextGetter(
+ MessageLoop* io_message_loop,
+ MessageLoop* file_message_loop)
+ : io_message_loop_proxy_(io_message_loop->message_loop_proxy()) {
+ proxy_config_service_.reset(
+ net::ProxyService::CreateSystemProxyConfigService(
+ io_message_loop, file_message_loop));
+}
+
+net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
+ if (!url_request_context_)
+ url_request_context_ =
+ new URLRequestContext(proxy_config_service_.get());
+ return url_request_context_;
+}
+
+scoped_refptr<base::MessageLoopProxy>
+URLRequestContextGetter::GetIOMessageLoopProxy() const {
+ return io_message_loop_proxy_;
+}
+
+URLRequestContextGetter::~URLRequestContextGetter() {}
+
+} // namespace remoting
diff --git a/remoting/host/url_request_context.h b/remoting/host/url_request_context.h
new file mode 100644
index 0000000..c8aaeaf
--- /dev/null
+++ b/remoting/host/url_request_context.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 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.
+
+#ifndef REMOTING_HOST_URL_REQUEST_CONTEXT_H_
+#define REMOTING_HOST_URL_REQUEST_CONTEXT_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "net/proxy/proxy_config_service.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_context_storage.h"
+
+namespace base {
+class MessageLoopProxy;
+} // namespace base
+
+namespace remoting {
+
+// Subclass of net::URLRequestContext which can be used to store extra
+// information for requests. This subclass is meant to be used in the
+// remoting Me2Me host process where the profile is not available.
+class URLRequestContext : public net::URLRequestContext {
+ public:
+ explicit URLRequestContext(net::ProxyConfigService* net_proxy_config_service);
+
+ private:
+ net::URLRequestContextStorage storage_;
+};
+
+class URLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+ URLRequestContextGetter(MessageLoop* io_message_loop,
+ MessageLoop* file_message_loop);
+ virtual ~URLRequestContextGetter();
+
+ // Overridden from net::URLRequestContextGetter:
+ virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
+ virtual scoped_refptr<base::MessageLoopProxy>
+ GetIOMessageLoopProxy() const OVERRIDE;
+
+ private:
+ scoped_refptr<net::URLRequestContext> url_request_context_;
+ scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+ scoped_ptr<net::ProxyConfigService> proxy_config_service_;
+};
+
+} // namespace remoting
+
+#endif // CHROME_SERVICE_NET_SERVICE_URL_REQUEST_CONTEXT_H_
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index c3ce7f6..5f959ec 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -505,6 +505,7 @@
'remoting_protocol',
'differ_block',
'../crypto/crypto.gyp:crypto',
+ '../content/content.gyp:content_common'
],
'sources': [
'host/capturer.h',
@@ -546,6 +547,8 @@
'host/event_executor_win.cc',
'host/heartbeat_sender.cc',
'host/heartbeat_sender.h',
+ 'host/gaia_oauth_client.cc',
+ 'host/gaia_oauth_client.h',
'host/host_config.cc',
'host/host_config.h',
'host/host_key_pair.cc',
@@ -567,6 +570,8 @@
'host/local_input_monitor_win.cc',
'host/log_to_server.cc',
'host/log_to_server.h',
+ 'host/oauth_client.cc',
+ 'host/oauth_client.h',
'host/policy_hack/nat_policy.h',
'host/policy_hack/nat_policy.cc',
'host/policy_hack/nat_policy_linux.cc',
@@ -582,6 +587,8 @@
'host/signaling_connector.h',
'host/ui_strings.cc',
'host/ui_strings.h',
+ 'host/url_request_context.cc',
+ 'host/url_request_context.h',
'host/usb_keycode_map.h',
'host/user_authenticator.h',
'host/user_authenticator_linux.cc',