summaryrefslogtreecommitdiffstats
path: root/google_apis
diff options
context:
space:
mode:
authormnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-19 11:21:12 +0000
committermnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-19 11:21:12 +0000
commit3014321f5622f30e8e7f88fdb55bcc0e612b4f65 (patch)
treee5e5c03075f8dcd6a8a5ae421b51514e6b8aaa46 /google_apis
parentc6f86d379547ea28ca4c3de64dd0c6cb0cfb2e87 (diff)
downloadchromium_src-3014321f5622f30e8e7f88fdb55bcc0e612b4f65.zip
chromium_src-3014321f5622f30e8e7f88fdb55bcc0e612b4f65.tar.gz
chromium_src-3014321f5622f30e8e7f88fdb55bcc0e612b4f65.tar.bz2
Add a fake GAIA implementation for use with the test server.
This is for the benefit of integration tests that need the browser to interface with GAIA and friends, such as for OAuth2 token minting. BUG=chromium:243889 R=joi@chromium.org, xiyuan@chromium.org, zelidrag@chromium.org Review URL: https://codereview.chromium.org/24172005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224108 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'google_apis')
-rw-r--r--google_apis/gaia/fake_gaia.cc143
-rw-r--r--google_apis/gaia/fake_gaia.h86
-rw-r--r--google_apis/gaia/gaia_urls.cc6
-rw-r--r--google_apis/gaia/gaia_urls.h2
-rw-r--r--google_apis/google_apis.gyp20
-rw-r--r--google_apis/test/service_login.html74
6 files changed, 331 insertions, 0 deletions
diff --git a/google_apis/gaia/fake_gaia.cc b/google_apis/gaia/fake_gaia.cc
new file mode 100644
index 0000000..9f4a812
--- /dev/null
+++ b/google_apis/gaia/fake_gaia.cc
@@ -0,0 +1,143 @@
+// 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 "google_apis/gaia/fake_gaia.h"
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "net/base/url_util.h"
+#include "net/http/http_status_code.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "url/url_parse.h"
+
+using namespace net::test_server;
+
+namespace {
+const base::FilePath::CharType kServiceLogin[] =
+ FILE_PATH_LITERAL("google_apis/test/service_login.html");
+}
+
+FakeGaia::AccessTokenInfo::AccessTokenInfo()
+ : expires_in(3600) {}
+
+FakeGaia::AccessTokenInfo::~AccessTokenInfo() {}
+
+FakeGaia::FakeGaia() {
+ base::FilePath source_root_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
+ CHECK(base::ReadFileToString(
+ source_root_dir.Append(base::FilePath(kServiceLogin)),
+ &service_login_response_));
+}
+
+FakeGaia::~FakeGaia() {}
+
+scoped_ptr<HttpResponse> FakeGaia::HandleRequest(const HttpRequest& request) {
+ GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+
+ // The scheme and host of the URL is actually not important but required to
+ // get a valid GURL in order to parse |request.relative_url|.
+ GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
+ std::string request_path = request_url.path();
+
+ scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
+ if (request_path == gaia_urls->service_login_url().path()) {
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content(service_login_response_);
+ http_response->set_content_type("text/html");
+ } else if (request_path == gaia_urls->service_login_auth_url().path()) {
+ std::string continue_url = gaia_urls->service_login_url().spec();
+ GetQueryParameter(request.content, "continue", &continue_url);
+ http_response->set_code(net::HTTP_OK);
+ const std::string redirect_js =
+ "document.location.href = '" + continue_url + "'";
+ http_response->set_content(
+ "<HTML><HEAD><SCRIPT>\n" + redirect_js + "\n</SCRIPT></HEAD></HTML>");
+ http_response->set_content_type("text/html");
+ } else if (request_path == gaia_urls->oauth2_token_url().path()) {
+ std::string refresh_token;
+ const AccessTokenInfo* token_info = NULL;
+ if (GetQueryParameter(request.content, "refresh_token", &refresh_token) &&
+ (token_info = GetAccessTokenInfo(refresh_token))) {
+ base::DictionaryValue response_dict;
+ response_dict.SetString("access_token", token_info->token);
+ response_dict.SetInteger("expires_in", 3600);
+ FormatJSONResponse(response_dict, http_response.get());
+ } else {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ }
+ } else if (request_path == gaia_urls->oauth2_token_info_url().path()) {
+ const AccessTokenInfo* token_info = NULL;
+ std::string access_token;
+ if (GetQueryParameter(request.content, "access_token", &access_token)) {
+ for (AccessTokenInfoMap::const_iterator entry(
+ access_token_info_map_.begin());
+ entry != access_token_info_map_.end();
+ ++entry) {
+ if (entry->second.token == access_token) {
+ token_info = &(entry->second);
+ break;
+ }
+ }
+ }
+
+ if (token_info) {
+ base::DictionaryValue response_dict;
+ response_dict.SetString("issued_to", token_info->issued_to);
+ response_dict.SetString("audience", token_info->audience);
+ response_dict.SetString("user_id", token_info->user_id);
+ std::vector<std::string> scope_vector(token_info->scopes.begin(),
+ token_info->scopes.end());
+ response_dict.SetString("scope", JoinString(scope_vector, " "));
+ response_dict.SetInteger("expires_in", token_info->expires_in);
+ response_dict.SetString("email", token_info->email);
+ FormatJSONResponse(response_dict, http_response.get());
+ } else {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ }
+ } else {
+ // Request not understood.
+ return scoped_ptr<HttpResponse>();
+ }
+
+ return http_response.PassAs<HttpResponse>();
+}
+
+void FakeGaia::IssueOAuthToken(const std::string& refresh_token,
+ const AccessTokenInfo& token_info) {
+ access_token_info_map_[refresh_token] = token_info;
+}
+
+void FakeGaia::FormatJSONResponse(const base::DictionaryValue& response_dict,
+ BasicHttpResponse* http_response) {
+ std::string response_json;
+ base::JSONWriter::Write(&response_dict, &response_json);
+ http_response->set_content(response_json);
+ http_response->set_code(net::HTTP_OK);
+}
+
+const FakeGaia::AccessTokenInfo* FakeGaia::GetAccessTokenInfo(
+ const std::string& refresh_token) const {
+ AccessTokenInfoMap::const_iterator entry =
+ access_token_info_map_.find(refresh_token);
+ return entry == access_token_info_map_.end() ? NULL : &entry->second;
+}
+
+// static
+bool FakeGaia::GetQueryParameter(const std::string& query,
+ const std::string& key,
+ std::string* value) {
+ // Name and scheme actually don't matter, but are required to get a valid URL
+ // for parsing.
+ GURL query_url("http://localhost?" + query);
+ return net::GetValueForKeyInQuery(query_url, key, value);
+}
diff --git a/google_apis/gaia/fake_gaia.h b/google_apis/gaia/fake_gaia.h
new file mode 100644
index 0000000..24f6891
--- /dev/null
+++ b/google_apis/gaia/fake_gaia.h
@@ -0,0 +1,86 @@
+// 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.
+
+#ifndef GOOGLE_APIS_GAIA_FAKE_GAIA_H_
+#define GOOGLE_APIS_GAIA_FAKE_GAIA_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace net {
+namespace test_server {
+class BasicHttpResponse;
+struct HttpRequest;
+class HttpResponse;
+}
+}
+
+// This is a test helper that implements a fake GAIA service for use in browser
+// tests. It's mainly intended for use with EmbeddedTestServer, for which it can
+// be registered as an additional request handler.
+class FakeGaia {
+ public:
+ typedef std::set<std::string> ScopeSet;
+
+ // Access token details used for token minting and the token info endpoint.
+ struct AccessTokenInfo {
+ AccessTokenInfo();
+ ~AccessTokenInfo();
+
+ std::string token;
+ std::string issued_to;
+ std::string audience;
+ std::string user_id;
+ ScopeSet scopes;
+ int expires_in;
+ std::string email;
+ };
+
+ FakeGaia();
+ ~FakeGaia();
+
+ // Handles a request and returns a response if the request was recognized as a
+ // GAIA request. Note that this respects the switches::kGaiaUrl and friends so
+ // that this can used with EmbeddedTestServer::RegisterRequestHandler().
+ scoped_ptr<net::test_server::HttpResponse> HandleRequest(
+ const net::test_server::HttpRequest& request);
+
+ // Configures an OAuth2 token that'll be returned when a client requests an
+ // access token for the given refresh token.
+ void IssueOAuthToken(const std::string& refresh_token,
+ const AccessTokenInfo& token_info);
+
+ private:
+ typedef std::map<std::string, AccessTokenInfo> AccessTokenInfoMap;
+
+ // Formats a JSON response with the data in |response_dict|.
+ void FormatJSONResponse(const base::DictionaryValue& response_dict,
+ net::test_server::BasicHttpResponse* http_response);
+
+ // Returns the access token associated with |refresh_token| or NULL if not
+ // found.
+ const AccessTokenInfo* GetAccessTokenInfo(
+ const std::string& refresh_token) const;
+
+ // Extracts the parameter named |key| from |query| and places it in |value|.
+ // Returns false if no parameter is found.
+ static bool GetQueryParameter(const std::string& query,
+ const std::string& key,
+ std::string* value);
+
+ AccessTokenInfoMap access_token_info_map_;
+ std::string service_login_response_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeGaia);
+};
+
+#endif // GOOGLE_APIS_GAIA_FAKE_GAIA_H_
diff --git a/google_apis/gaia/gaia_urls.cc b/google_apis/gaia/gaia_urls.cc
index f976f6c..e5e5b8f 100644
--- a/google_apis/gaia/gaia_urls.cc
+++ b/google_apis/gaia/gaia_urls.cc
@@ -18,6 +18,7 @@ const char kDefaultGoogleApisBaseUrl[] = "https://www.googleapis.com";
// API calls from accounts.google.com
const char kClientLoginUrlSuffix[] = "ClientLogin";
const char kServiceLoginUrlSuffix[] = "ServiceLogin";
+const char kServiceLoginAuthUrlSuffix[] = "ServiceLoginAuth";
const char kServiceLogoutUrlSuffix[] = "Logout";
const char kIssueAuthTokenUrlSuffix[] = "IssueAuthToken";
const char kGetUserInfoUrlSuffix[] = "GetUserInfo";
@@ -92,6 +93,7 @@ GaiaUrls::GaiaUrls() {
// URLs from accounts.google.com.
client_login_url_ = gaia_url_.Resolve(kClientLoginUrlSuffix);
service_login_url_ = gaia_url_.Resolve(kServiceLoginUrlSuffix);
+ service_login_auth_url_ = gaia_url_.Resolve(kServiceLoginAuthUrlSuffix);
service_logout_url_ = gaia_url_.Resolve(kServiceLogoutUrlSuffix);
issue_auth_token_url_ = gaia_url_.Resolve(kIssueAuthTokenUrlSuffix);
get_user_info_url_ = gaia_url_.Resolve(kGetUserInfoUrlSuffix);
@@ -149,6 +151,10 @@ const GURL& GaiaUrls::service_login_url() const {
return service_login_url_;
}
+const GURL& GaiaUrls::service_login_auth_url() const {
+ return service_login_auth_url_;
+}
+
const GURL& GaiaUrls::service_logout_url() const {
return service_logout_url_;
}
diff --git a/google_apis/gaia/gaia_urls.h b/google_apis/gaia/gaia_urls.h
index 06014d2..e06b95d 100644
--- a/google_apis/gaia/gaia_urls.h
+++ b/google_apis/gaia/gaia_urls.h
@@ -20,6 +20,7 @@ class GaiaUrls {
const GURL& captcha_base_url() const;
const GURL& client_login_url() const;
const GURL& service_login_url() const;
+ const GURL& service_login_auth_url() const;
const GURL& service_logout_url() const;
const GURL& issue_auth_token_url() const;
const GURL& get_user_info_url() const;
@@ -60,6 +61,7 @@ class GaiaUrls {
GURL client_login_url_;
GURL service_login_url_;
+ GURL service_login_auth_url_;
GURL service_logout_url_;
GURL issue_auth_token_url_;
GURL get_user_info_url_;
diff --git a/google_apis/google_apis.gyp b/google_apis/google_apis.gyp
index 3479567..762c3695 100644
--- a/google_apis/google_apis.gyp
+++ b/google_apis/google_apis.gyp
@@ -106,5 +106,25 @@
'google_api_keys_unittest.cc',
],
},
+ {
+ 'target_name': 'google_apis_test_support',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/base.gyp:test_support_base',
+ '../net/net.gyp:net',
+ '../net/net.gyp:net_test_support',
+ ],
+ 'export_dependent_settings': [
+ '../base/base.gyp:base',
+ '../base/base.gyp:test_support_base',
+ '../net/net.gyp:net',
+ '../net/net.gyp:net_test_support',
+ ],
+ 'sources': [
+ 'gaia/fake_gaia.cc',
+ 'gaia/fake_gaia.h',
+ ],
+ },
],
}
diff --git a/google_apis/test/service_login.html b/google_apis/test/service_login.html
new file mode 100644
index 0000000..d605707
--- /dev/null
+++ b/google_apis/test/service_login.html
@@ -0,0 +1,74 @@
+<HTML>
+<HEAD>
+<SCRIPT>
+var gaia = gaia || {};
+gaia.chromeOSLogin = {};
+
+gaia.chromeOSLogin.parent_page_url_ =
+'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/main.html';
+
+gaia.chromeOSLogin.attemptLogin = function(email, password, attemptToken) {
+ var msg = {
+ 'method': 'attemptLogin',
+ 'email': email,
+ 'password': password,
+ 'attemptToken': attemptToken
+ };
+ window.parent.postMessage(msg, gaia.chromeOSLogin.parent_page_url_);
+};
+
+gaia.chromeOSLogin.clearOldAttempts = function() {
+ var msg = {
+ 'method': 'clearOldAttempts'
+ };
+ window.parent.postMessage(msg, gaia.chromeOSLogin.parent_page_url_);
+};
+
+gaia.chromeOSLogin.onAttemptedLogin = function(emailFormElement,
+ passwordFormElement,
+ continueUrlElement) {
+ var email = emailFormElement.value;
+ var passwd = passwordFormElement.value;
+ var attemptToken = new Date().getTime();
+
+ gaia.chromeOSLogin.attemptLogin(email, passwd, attemptToken);
+
+ if (continueUrlElement) {
+ var prevAttemptIndex = continueUrlElement.value.indexOf('?attemptToken');
+ if (prevAttemptIndex != -1) {
+ continueUrlElement.value =
+ continueUrlElement.value.substr(0, prevAttemptIndex);
+ }
+ continueUrlElement.value += '?attemptToken=' + attemptToken;
+ }
+};
+
+function submitAndGo() {
+ gaia.chromeOSLogin.onAttemptedLogin(document.getElementById("Email"),
+ document.getElementById("Passwd"),
+ document.getElementById("continue"));
+ return true;
+}
+
+function onAuthError() {
+ if (window.domAutomationController) {
+ window.domAutomationController.sendWithId(4444, 'loginfail');
+ }
+}
+
+function onLoad() {
+ gaia.chromeOSLogin.clearOldAttempts();
+}
+</SCRIPT>
+</HEAD>
+<BODY onload='onLoad();'>
+ Local Auth Server:<BR>
+ <FORM action='/ServiceLoginAuth' method=POST onsubmit='submitAndGo()'>
+ <INPUT TYPE=text id="Email" name="Email">
+ <INPUT TYPE=text id="Passwd" name="Passwd">
+ <INPUT TYPE=hidden id="continue" name="continue"
+ value="chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/success.html">
+ <INPUT TYPE=Submit id="signIn">
+ </FORM>
+</BODY>
+</HTML>