summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/login/kiosk_browsertest.cc159
-rw-r--r--chrome/browser/chromeos/login/oauth2_browsertest.cc179
-rw-r--r--chrome/browser/chromeos/login/oauth2_login_manager_factory.h1
-rw-r--r--chrome/browser/chromeos/login/oauth2_login_verifier.cc2
-rw-r--r--chrome/browser/chromeos/login/oobe_base_test.cc171
-rw-r--r--chrome/browser/chromeos/login/oobe_base_test.h70
-rw-r--r--chrome/browser/chromeos/login/oobe_browsertest.cc1
-rw-r--r--chrome/browser/chromeos/login/saml_browsertest.cc15
-rw-r--r--chrome/chrome_tests.gypi3
-rw-r--r--google_apis/gaia/fake_gaia.cc439
-rw-r--r--google_apis/gaia/fake_gaia.h64
11 files changed, 843 insertions, 261 deletions
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 4969217..dee046a 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -8,73 +8,33 @@
#include "ash/desktop_background/desktop_background_controller.h"
#include "ash/desktop_background/desktop_background_controller_observer.h"
#include "ash/shell.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/location.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
-#include "base/prefs/scoped_user_pref_update.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_browser_main.h"
-#include "chrome/browser/chrome_browser_main_extra_parts.h"
-#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/login/app_launch_controller.h"
-#include "chrome/browser/chromeos/login/app_launch_signin_screen.h"
-#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/fake_user_manager.h"
-#include "chrome/browser/chromeos/login/login_display_host_impl.h"
#include "chrome/browser/chromeos/login/mock_user_manager.h"
+#include "chrome/browser/chromeos/login/oobe_base_test.h"
#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
-#include "chrome/browser/chromeos/login/webui_login_display.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
-#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
-#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/interactive_test_utils.h"
-#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/chromeos_switches.h"
-#include "chromeos/settings/cros_settings_names.h"
-#include "components/policy/core/common/cloud/policy_builder.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_utils.h"
-#include "extensions/common/extension.h"
-#include "google_apis/gaia/fake_gaia.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_switches.h"
#include "google_apis/gaia/gaia_urls.h"
-#include "net/base/network_change_notifier.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/embedded_test_server/http_request.h"
-#include "net/test/embedded_test_server/http_response.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer.h"
namespace em = enterprise_management;
@@ -111,9 +71,6 @@ const char kTestClientId[] = "fake-client-id";
const char kTestAppScope[] =
"https://www.googleapis.com/auth/userinfo.profile";
-// Note the path name must be the same as in shill stub.
-const char kStubEthernetServicePath[] = "eth1";
-
// Helper function for GetConsumerKioskModeStatusCallback.
void ConsumerKioskModeStatusCheck(
KioskAppManager::ConsumerKioskModeStatus* out_status,
@@ -231,7 +188,7 @@ class ShellWindowObserver : public apps::ShellWindowRegistry::Observer {
DISALLOW_COPY_AND_ASSIGN(ShellWindowObserver);
};
-class KioskTest : public InProcessBrowserTest {
+class KioskTest : public OobeBaseTest {
public:
KioskTest() {
set_exit_when_last_browser_closes(false);
@@ -240,48 +197,20 @@ class KioskTest : public InProcessBrowserTest {
virtual ~KioskTest() {}
protected:
- virtual void SetUp() OVERRIDE {
- base::FilePath test_data_dir;
- PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
- embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
- embedded_test_server()->RegisterRequestHandler(
- base::Bind(&FakeGaia::HandleRequest, base::Unretained(&fake_gaia_)));
- ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
- // Stop IO thread here because no threads are allowed while
- // spawning sandbox host process. See crbug.com/322732.
- embedded_test_server()->StopThread();
+ virtual void SetUp() OVERRIDE {
mock_user_manager_.reset(new MockUserManager);
AppLaunchController::SkipSplashWaitForTesting();
AppLaunchController::SetNetworkWaitForTesting(kTestNetworkTimeoutSeconds);
- InProcessBrowserTest::SetUp();
- }
-
- virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
- host_resolver()->AddRule("*", "127.0.0.1");
-
- network_portal_detector_ = new NetworkPortalDetectorTestImpl();
- NetworkPortalDetector::InitializeForTesting(network_portal_detector_);
- network_portal_detector_->SetDefaultNetworkPathForTesting(
- kStubEthernetServicePath);
- }
-
- virtual void SetUpOnMainThread() OVERRIDE {
- // Restart the thread as the sandbox host process has already been spawned.
- embedded_test_server()->RestartThreadAndListen();
+ OobeBaseTest::SetUp();
}
virtual void CleanUpOnMainThread() OVERRIDE {
AppLaunchController::SetNetworkTimeoutCallbackForTesting(NULL);
AppLaunchSigninScreen::SetUserManagerForTesting(NULL);
- // If the login display is still showing, exit gracefully.
- if (LoginDisplayHostImpl::default_host()) {
- base::MessageLoop::current()->PostTask(FROM_HERE,
- base::Bind(&chrome::AttemptExit));
- content::RunMessageLoop();
- }
+ OobeBaseTest::CleanUpOnMainThread();
// Clean up while main thread still runs.
// See http://crbug.com/176659.
@@ -289,25 +218,12 @@ class KioskTest : public InProcessBrowserTest {
}
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
- command_line->AppendSwitch(chromeos::switches::kLoginManager);
- command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
- command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
- command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
+ OobeBaseTest::SetUpCommandLine(command_line);
// Create gaia and webstore URL from test server url but using different
// host names. This is to avoid gaia response being tagged as from
// webstore in chrome_resource_dispatcher_host_delegate.cc.
const GURL& server_url = embedded_test_server()->base_url();
-
- std::string gaia_host("gaia");
- GURL::Replacements replace_gaia_host;
- replace_gaia_host.SetHostStr(gaia_host);
- GURL gaia_url = server_url.ReplaceComponents(replace_gaia_host);
- command_line->AppendSwitchASCII(::switches::kGaiaUrl, gaia_url.spec());
- command_line->AppendSwitchASCII(::switches::kLsoUrl, gaia_url.spec());
- command_line->AppendSwitchASCII(::switches::kGoogleApisUrl,
- gaia_url.spec());
-
std::string webstore_host("webstore");
GURL::Replacements replace_webstore_host;
replace_webstore_host.SetHostStr(webstore_host);
@@ -408,46 +324,6 @@ class KioskTest : public InProcessBrowserTest {
EXPECT_TRUE(launch_data_check_listener.was_satisfied());
}
- void SimulateNetworkOffline() {
- NetworkPortalDetector::CaptivePortalState offline_state;
- offline_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE;
- network_portal_detector_->SetDetectionResultsForTesting(
- kStubEthernetServicePath, offline_state);
- network_portal_detector_->NotifyObserversForTesting();
- }
-
- base::Closure SimulateNetworkOfflineClosure() {
- return base::Bind(&KioskTest::SimulateNetworkOffline,
- base::Unretained(this));
- }
-
- void SimulateNetworkOnline() {
- NetworkPortalDetector::CaptivePortalState online_state;
- online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
- online_state.response_code = 204;
- network_portal_detector_->SetDetectionResultsForTesting(
- kStubEthernetServicePath, online_state);
- network_portal_detector_->NotifyObserversForTesting();
- }
-
- base::Closure SimulateNetworkOnlineClosure() {
- return base::Bind(&KioskTest::SimulateNetworkOnline,
- base::Unretained(this));
- }
-
- void SimulateNetworkPortal() {
- NetworkPortalDetector::CaptivePortalState portal_state;
- portal_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
- network_portal_detector_->SetDetectionResultsForTesting(
- kStubEthernetServicePath, portal_state);
- network_portal_detector_->NotifyObserversForTesting();
- }
-
- base::Closure SimulateNetworkPortalClosure() {
- return base::Bind(&KioskTest::SimulateNetworkPortal,
- base::Unretained(this));
- }
-
void WaitForAppLaunchNetworkTimeout() {
if (GetAppLaunchController()->network_wait_timedout())
return;
@@ -491,35 +367,12 @@ class KioskTest : public InProcessBrowserTest {
return status;
}
- void JsExpect(const std::string& expression) {
- bool result;
- ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
- GetLoginUI()->GetWebContents(),
- "window.domAutomationController.send(!!(" + expression + "));",
- &result));
- ASSERT_TRUE(result) << expression;
- }
-
- content::WebUI* GetLoginUI() {
- return static_cast<chromeos::LoginDisplayHostImpl*>(
- chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI()->web_ui();
- }
-
- SigninScreenHandler* GetSigninScreenHandler() {
- return static_cast<chromeos::LoginDisplayHostImpl*>(
- chromeos::LoginDisplayHostImpl::default_host())
- ->GetOobeUI()
- ->signin_screen_handler_for_test();
- }
-
AppLaunchController* GetAppLaunchController() {
return chromeos::LoginDisplayHostImpl::default_host()
->GetAppLaunchController();
}
- FakeGaia fake_gaia_;
scoped_ptr<MockUserManager> mock_user_manager_;
- NetworkPortalDetectorTestImpl* network_portal_detector_;
};
IN_PROC_BROWSER_TEST_F(KioskTest, InstallAndLaunchApp) {
diff --git a/chrome/browser/chromeos/login/oauth2_browsertest.cc b/chrome/browser/chromeos/login/oauth2_browsertest.cc
new file mode 100644
index 0000000..bbbed3e
--- /dev/null
+++ b/chrome/browser/chromeos/login/oauth2_browsertest.cc
@@ -0,0 +1,179 @@
+// 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 "base/message_loop/message_loop.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/oauth2_login_manager.h"
+#include "chrome/browser/chromeos/login/oauth2_login_manager_factory.h"
+#include "chrome/browser/chromeos/login/oobe_base_test.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
+#include "content/public/browser/notification_service.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_urls.h"
+
+namespace chromeos {
+
+namespace {
+
+// Email of owner account for test.
+const char kTestAccountId[] = "username@gmail.com";
+
+const char kTestAuthCode[] = "fake-auth-code";
+const char kTestGaiaUberToken[] = "fake-uber-token";
+const char kTestAuthLoginAccessToken[] = "fake-access-token";
+const char kTestRefreshToken[] = "fake-refresh-token";
+const char kTestSessionSIDCookie[] = "fake-session-SID-cookie";
+const char kTestSessionLSIDCookie[] = "fake-session-LSID-cookie";
+const char kTestUserinfoToken[] = "fake-userinfo-token";
+const char kTestLoginToken[] = "fake-login-token";
+const char kTestSyncToken[] = "fake-sync-token";
+const char kTestAuthLoginToken[] = "fake-oauthlogin-token";
+
+} // namespace
+
+class OAuth2Test : public OobeBaseTest {
+ protected:
+ OAuth2Test() {}
+
+ virtual void SetUpOnMainThread() OVERRIDE {
+ OobeBaseTest::SetUpOnMainThread();
+
+ // Configure OAuth authentication.
+ GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+
+ fake_gaia_.SetAuthTokens(kTestAuthCode,
+ kTestRefreshToken,
+ kTestAuthLoginAccessToken,
+ kTestGaiaUberToken,
+ kTestSessionSIDCookie,
+ kTestSessionLSIDCookie);
+ // This token satisfies the userinfo.email request from
+ // DeviceOAuth2TokenService used in token validation.
+ FakeGaia::AccessTokenInfo userinfo_token_info;
+ userinfo_token_info.token = kTestUserinfoToken;
+ userinfo_token_info.scopes.insert(
+ "https://www.googleapis.com/auth/userinfo.email");
+ userinfo_token_info.audience = gaia_urls->oauth2_chrome_client_id();
+ userinfo_token_info.email = kTestAccountId;
+ fake_gaia_.IssueOAuthToken(kTestRefreshToken, userinfo_token_info);
+
+ FakeGaia::AccessTokenInfo userinfo_profile_token_info;
+ userinfo_profile_token_info.token = kTestUserinfoToken;
+ userinfo_profile_token_info.scopes.insert(
+ "https://www.googleapis.com/auth/userinfo.profile");
+ userinfo_profile_token_info.audience = gaia_urls->oauth2_chrome_client_id();
+ userinfo_profile_token_info.email = kTestAccountId;
+ fake_gaia_.IssueOAuthToken(kTestRefreshToken, userinfo_profile_token_info);
+
+ // The any-api access token for accessing the token minting endpoint.
+ FakeGaia::AccessTokenInfo login_token_info;
+ login_token_info.token = kTestLoginToken;
+ login_token_info.scopes.insert(GaiaConstants::kAnyApiOAuth2Scope);
+ login_token_info.audience = gaia_urls->oauth2_chrome_client_id();
+ fake_gaia_.IssueOAuthToken(kTestRefreshToken, login_token_info);
+
+ // The /auth/chromesync access token for accessing sync endpoint.
+ FakeGaia::AccessTokenInfo sync_token_info;
+ sync_token_info.token = kTestSyncToken;
+ sync_token_info.scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
+ sync_token_info.audience = gaia_urls->oauth2_chrome_client_id();
+ fake_gaia_.IssueOAuthToken(kTestRefreshToken, sync_token_info);
+
+ FakeGaia::AccessTokenInfo auth_login_token_info;
+ auth_login_token_info.token = kTestAuthLoginToken;
+ auth_login_token_info.scopes.insert(gaia_urls->oauth1_login_scope());
+ auth_login_token_info.audience = gaia_urls->oauth2_chrome_client_id();
+ fake_gaia_.IssueOAuthToken(kTestRefreshToken, auth_login_token_info);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OAuth2Test);
+};
+
+class OAuth2LoginManagerStateWaiter : public OAuth2LoginManager::Observer {
+ public:
+ explicit OAuth2LoginManagerStateWaiter(Profile* profile)
+ : profile_(profile),
+ waiting_for_state_(false),
+ final_state_(OAuth2LoginManager::SESSION_RESTORE_NOT_STARTED) {
+ }
+
+ void WaitForStates(
+ const std::set<OAuth2LoginManager::SessionRestoreState>& states) {
+ DCHECK(!waiting_for_state_);
+ OAuth2LoginManager* login_manager =
+ OAuth2LoginManagerFactory::GetInstance()->GetForProfile(profile_);
+ states_ = states;
+ if (states_.find(login_manager->state()) != states_.end()) {
+ final_state_ = login_manager->state();
+ return;
+ }
+
+ waiting_for_state_ = true;
+ login_manager->AddObserver(this);
+ runner_ = new content::MessageLoopRunner;
+ runner_->Run();
+ login_manager->RemoveObserver(this);
+ }
+
+ OAuth2LoginManager::SessionRestoreState final_state() { return final_state_; }
+
+ private:
+ // OAuth2LoginManager::Observer overrides.
+ virtual void OnSessionRestoreStateChanged(
+ Profile* user_profile,
+ OAuth2LoginManager::SessionRestoreState state) OVERRIDE {
+ if (!waiting_for_state_)
+ return;
+
+ if (states_.find(state) == states_.end())
+ return;
+
+ final_state_ = state;
+ waiting_for_state_ = false;
+ runner_->Quit();
+ }
+
+ Profile* profile_;
+ std::set<OAuth2LoginManager::SessionRestoreState> states_;
+ bool waiting_for_state_;
+ OAuth2LoginManager::SessionRestoreState final_state_;
+ scoped_refptr<content::MessageLoopRunner> runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(OAuth2LoginManagerStateWaiter);
+};
+
+IN_PROC_BROWSER_TEST_F(OAuth2Test, NewUser) {
+ SimulateNetworkOnline();
+ chromeos::WizardController::SkipPostLoginScreensForTesting();
+ chromeos::WizardController* wizard_controller =
+ chromeos::WizardController::default_controller();
+ wizard_controller->SkipToLoginForTesting(LoginScreenContext());
+
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+ content::NotificationService::AllSources()).Wait();
+
+ // Use capitalized and dotted user name on purpose to make sure
+ // our email normalization kicks in.
+ GetLoginDisplay()->ShowSigninScreenForCreds("User.Name", "password");
+
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_SESSION_STARTED,
+ content::NotificationService::AllSources()).Wait();
+
+ std::set<OAuth2LoginManager::SessionRestoreState> states;
+ states.insert(OAuth2LoginManager::SESSION_RESTORE_DONE);
+ states.insert(OAuth2LoginManager::SESSION_RESTORE_FAILED);
+ states.insert(OAuth2LoginManager::SESSION_RESTORE_CONNECTION_FAILED);
+ OAuth2LoginManagerStateWaiter merge_session_waiter(
+ ProfileManager::GetPrimaryUserProfile());
+ merge_session_waiter.WaitForStates(states);
+ EXPECT_EQ(merge_session_waiter.final_state(),
+ OAuth2LoginManager::SESSION_RESTORE_DONE);
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/oauth2_login_manager_factory.h b/chrome/browser/chromeos/login/oauth2_login_manager_factory.h
index 8de820e7..0dde695 100644
--- a/chrome/browser/chromeos/login/oauth2_login_manager_factory.h
+++ b/chrome/browser/chromeos/login/oauth2_login_manager_factory.h
@@ -8,6 +8,7 @@
#include "base/memory/singleton.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+class BrowserContextKeyedService;
class Profile;
namespace chromeos {
diff --git a/chrome/browser/chromeos/login/oauth2_login_verifier.cc b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
index 4f48206..593921e 100644
--- a/chrome/browser/chromeos/login/oauth2_login_verifier.cc
+++ b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
@@ -76,7 +76,7 @@ void OAuth2LoginVerifier::VerifyProfileTokens(Profile* profile) {
(detector && detector->GetCaptivePortalState(default_network).status !=
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE)) {
// If network is offline, defer the token fetching until online.
- VLOG(1) << "Network is offline. Deferring OAuth2 access token fetch.";
+ LOG(WARNING) << "Network is offline. Deferring OAuth2 access token fetch.";
BrowserThread::PostDelayedTask(
BrowserThread::UI,
FROM_HERE,
diff --git a/chrome/browser/chromeos/login/oobe_base_test.cc b/chrome/browser/chromeos/login/oobe_base_test.cc
new file mode 100644
index 0000000..090be6d
--- /dev/null
+++ b/chrome/browser/chromeos/login/oobe_base_test.cc
@@ -0,0 +1,171 @@
+// 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/chromeos/login/oobe_base_test.h"
+
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/existing_user_controller.h"
+#include "chrome/browser/chromeos/login/fake_user_manager.h"
+#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chromeos/chromeos_switches.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/browser_test_utils.h"
+#include "google_apis/gaia/gaia_switches.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+
+namespace chromeos {
+
+namespace {
+
+// Note the path name must be the same as in shill stub.
+const char kStubEthernetServicePath[] = "eth1";
+
+} // namespace
+
+OobeBaseTest::OobeBaseTest() : network_portal_detector_(NULL) {
+ set_exit_when_last_browser_closes(false);
+}
+
+OobeBaseTest::~OobeBaseTest() {
+}
+
+void OobeBaseTest::SetUp() {
+ base::FilePath test_data_dir;
+ PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
+ embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&FakeGaia::HandleRequest, base::Unretained(&fake_gaia_)));
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ // Stop IO thread here because no threads are allowed while
+ // spawning sandbox host process. See crbug.com/322732.
+ embedded_test_server()->StopThread();
+
+ InProcessBrowserTest::SetUp();
+}
+
+void OobeBaseTest::SetUpInProcessBrowserTestFixture() {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ network_portal_detector_ = new NetworkPortalDetectorTestImpl();
+ NetworkPortalDetector::InitializeForTesting(network_portal_detector_);
+ network_portal_detector_->SetDefaultNetworkPathForTesting(
+ kStubEthernetServicePath);
+}
+
+void OobeBaseTest::SetUpOnMainThread() {
+ // Restart the thread as the sandbox host process has already been spawned.
+ embedded_test_server()->RestartThreadAndListen();
+}
+
+void OobeBaseTest::CleanUpOnMainThread() {
+ // If the login display is still showing, exit gracefully.
+ if (LoginDisplayHostImpl::default_host()) {
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&chrome::AttemptExit));
+ content::RunMessageLoop();
+ }
+}
+
+void OobeBaseTest::SetUpCommandLine(CommandLine* command_line) {
+ command_line->AppendSwitch(chromeos::switches::kLoginManager);
+ command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
+ command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
+ command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
+
+ // Create gaia and webstore URL from test server url but using different
+ // host names. This is to avoid gaia response being tagged as from
+ // webstore in chrome_resource_dispatcher_host_delegate.cc.
+ const GURL& server_url = embedded_test_server()->base_url();
+
+ std::string gaia_host("gaia");
+ GURL::Replacements replace_gaia_host;
+ replace_gaia_host.SetHostStr(gaia_host);
+ GURL gaia_url = server_url.ReplaceComponents(replace_gaia_host);
+ command_line->AppendSwitchASCII(::switches::kGaiaUrl, gaia_url.spec());
+ command_line->AppendSwitchASCII(::switches::kLsoUrl, gaia_url.spec());
+ command_line->AppendSwitchASCII(::switches::kGoogleApisUrl,
+ gaia_url.spec());
+ fake_gaia_.Initialize();
+}
+
+void OobeBaseTest::SimulateNetworkOffline() {
+ NetworkPortalDetector::CaptivePortalState offline_state;
+ offline_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE;
+ network_portal_detector_->SetDetectionResultsForTesting(
+ kStubEthernetServicePath, offline_state);
+ network_portal_detector_->NotifyObserversForTesting();
+}
+
+base::Closure OobeBaseTest::SimulateNetworkOfflineClosure() {
+ return base::Bind(&OobeBaseTest::SimulateNetworkOffline,
+ base::Unretained(this));
+}
+
+void OobeBaseTest::SimulateNetworkOnline() {
+ NetworkPortalDetector::CaptivePortalState online_state;
+ online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
+ online_state.response_code = 204;
+ network_portal_detector_->SetDetectionResultsForTesting(
+ kStubEthernetServicePath, online_state);
+ network_portal_detector_->NotifyObserversForTesting();
+}
+
+base::Closure OobeBaseTest::SimulateNetworkOnlineClosure() {
+ return base::Bind(&OobeBaseTest::SimulateNetworkOnline,
+ base::Unretained(this));
+}
+
+void OobeBaseTest::SimulateNetworkPortal() {
+ NetworkPortalDetector::CaptivePortalState portal_state;
+ portal_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
+ network_portal_detector_->SetDetectionResultsForTesting(
+ kStubEthernetServicePath, portal_state);
+ network_portal_detector_->NotifyObserversForTesting();
+}
+
+base::Closure OobeBaseTest::SimulateNetworkPortalClosure() {
+ return base::Bind(&OobeBaseTest::SimulateNetworkPortal,
+ base::Unretained(this));
+}
+
+void OobeBaseTest::JsExpect(const std::string& expression) {
+ bool result;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetLoginUI()->GetWebContents(),
+ "window.domAutomationController.send(!!(" + expression + "));",
+ &result));
+ ASSERT_TRUE(result) << expression;
+}
+
+content::WebUI* OobeBaseTest::GetLoginUI() {
+ return static_cast<chromeos::LoginDisplayHostImpl*>(
+ chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI()->web_ui();
+}
+
+SigninScreenHandler* OobeBaseTest::GetSigninScreenHandler() {
+ return static_cast<chromeos::LoginDisplayHostImpl*>(
+ chromeos::LoginDisplayHostImpl::default_host())
+ ->GetOobeUI()
+ ->signin_screen_handler_for_test();
+}
+
+WebUILoginDisplay* OobeBaseTest::GetLoginDisplay() {
+ ExistingUserController* controller =
+ ExistingUserController::current_controller();
+ CHECK(controller);
+ return static_cast<WebUILoginDisplay*>(
+ controller->login_display());
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/oobe_base_test.h b/chrome/browser/chromeos/login/oobe_base_test.h
new file mode 100644
index 0000000..5901f0a
--- /dev/null
+++ b/chrome/browser/chromeos/login/oobe_base_test.h
@@ -0,0 +1,70 @@
+// Copyright 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 CHROME_BROWSER_CHROMEOS_LOGIN_OOBE_BASE_TEST_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_OOBE_BASE_TEST_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "chrome/browser/chromeos/login/login_display_host_impl.h"
+#include "chrome/browser/chromeos/login/webui_login_display.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/test_utils.h"
+#include "google_apis/gaia/fake_gaia.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace content {
+class WebUI;
+} // namespace content
+
+namespace chromeos {
+
+class FakeUserManager;
+class NetworkPortalDetectorTestImpl;
+class SigninScreenHandler;
+
+// Base class for OOBE and Kiosk tests.
+class OobeBaseTest : public InProcessBrowserTest {
+ public:
+ OobeBaseTest();
+ virtual ~OobeBaseTest();
+
+ protected:
+ // InProcessBrowserTest overrides.
+ virtual void SetUp() OVERRIDE;
+ virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
+ virtual void SetUpOnMainThread() OVERRIDE;
+ virtual void CleanUpOnMainThread() OVERRIDE;
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+
+ // Network status control functions.
+ void SimulateNetworkOffline();
+ void SimulateNetworkOnline();
+ void SimulateNetworkPortal();
+
+ base::Closure SimulateNetworkOfflineClosure();
+ base::Closure SimulateNetworkOnlineClosure();
+ base::Closure SimulateNetworkPortalClosure();
+
+ // Checks JavaScript |expression| in login screen.
+ void JsExpect(const std::string& expression);
+
+ // Returns chrome://oobe WebUI.
+ content::WebUI* GetLoginUI();
+
+ // Returns SigninScreenHandler for login screen.
+ SigninScreenHandler* GetSigninScreenHandler();
+
+ // Returns login display.
+ WebUILoginDisplay* GetLoginDisplay();
+
+ FakeGaia fake_gaia_;
+ NetworkPortalDetectorTestImpl* network_portal_detector_;
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_OOBE_BASE_TEST_H_
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index b0e51c4..04483ea 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -38,6 +38,7 @@ class OobeTest : public InProcessBrowserTest {
command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
command_line->AppendSwitchASCII(
chromeos::switches::kAuthExtensionPath, "gaia_auth");
+ fake_gaia_.Initialize();
}
virtual void SetUpOnMainThread() OVERRIDE {
diff --git a/chrome/browser/chromeos/login/saml_browsertest.cc b/chrome/browser/chromeos/login/saml_browsertest.cc
index af8c2a0..6b55bce4 100644
--- a/chrome/browser/chromeos/login/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml_browsertest.cc
@@ -36,6 +36,13 @@ namespace chromeos {
namespace {
+const char kTestAuthCode[] = "fake-auth-code";
+const char kTestGaiaUberToken[] = "fake-uber-token";
+const char kTestAuthLoginAccessToken[] = "fake-access-token";
+const char kTestRefreshToken[] = "fake-refresh-token";
+const char kTestSessionSIDCookie[] = "fake-session-SID-cookie";
+const char kTestSessionLSIDCookie[] = "fake-session-LSID-cookie";
+
const char kRelayState[] = "RelayState";
const char kDefaultIdpHtml[] =
@@ -155,6 +162,7 @@ class SamlTest : public InProcessBrowserTest {
command_line->AppendSwitchASCII(::switches::kLsoUrl, gaia_url_.spec());
command_line->AppendSwitchASCII(::switches::kGoogleApisUrl,
gaia_url_.spec());
+ fake_gaia_.Initialize();
std::string saml_idp_host("saml.idp");
GURL::Replacements replace_saml_idp_host;
@@ -167,6 +175,13 @@ class SamlTest : public InProcessBrowserTest {
}
virtual void SetUpOnMainThread() OVERRIDE {
+ fake_gaia_.SetAuthTokens(kTestAuthCode,
+ kTestRefreshToken,
+ kTestAuthLoginAccessToken,
+ kTestGaiaUberToken,
+ kTestSessionSIDCookie,
+ kTestSessionLSIDCookie);
+
embedded_test_server()->RegisterRequestHandler(
base::Bind(&FakeGaia::HandleRequest, base::Unretained(&fake_gaia_)));
embedded_test_server()->RegisterRequestHandler(base::Bind(
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index c6706ad..4c70e74 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1022,6 +1022,9 @@
'browser/chromeos/login/mock_authenticator.cc',
'browser/chromeos/login/mock_authenticator.h',
'browser/chromeos/login/saml_browsertest.cc',
+ 'browser/chromeos/login/oauth2_browsertest.cc',
+ 'browser/chromeos/login/oobe_base_test.cc',
+ 'browser/chromeos/login/oobe_base_test.h',
'browser/chromeos/login/session_login_browsertest.cc',
'browser/chromeos/login/screen_locker_tester.cc',
'browser/chromeos/login/screen_locker_tester.h',
diff --git a/google_apis/gaia/fake_gaia.cc b/google_apis/gaia/fake_gaia.cc
index 7474aca8..9eddd85 100644
--- a/google_apis/gaia/fake_gaia.cc
+++ b/google_apis/gaia/fake_gaia.cc
@@ -7,6 +7,8 @@
#include <vector>
#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/json/json_writer.h"
@@ -15,6 +17,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/base/url_util.h"
@@ -23,11 +26,25 @@
#include "net/test/embedded_test_server/http_response.h"
#include "url/url_parse.h"
+#define REGISTER_RESPONSE_HANDLER(url, method) \
+ request_handlers_.insert(std::make_pair( \
+ url.path(), base::Bind(&FakeGaia::method, base::Unretained(this))))
+
+#define REGISTER_PATH_RESPONSE_HANDLER(path, method) \
+ request_handlers_.insert(std::make_pair( \
+ path, base::Bind(&FakeGaia::method, base::Unretained(this))))
+
using namespace net::test_server;
namespace {
+
const base::FilePath::CharType kServiceLogin[] =
FILE_PATH_LITERAL("google_apis/test/service_login.html");
+
+// OAuth2 Authentication header value prefix.
+const char kAuthHeaderBearer[] = "Bearer ";
+const char kAuthHeaderOAuth[] = "OAuth ";
+
}
FakeGaia::AccessTokenInfo::AccessTokenInfo()
@@ -45,113 +62,310 @@ FakeGaia::FakeGaia() {
FakeGaia::~FakeGaia() {}
-scoped_ptr<HttpResponse> FakeGaia::HandleRequest(const HttpRequest& request) {
+void FakeGaia::SetAuthTokens(const std::string& auth_code,
+ const std::string& refresh_token,
+ const std::string& access_token,
+ const std::string& gaia_uber_token,
+ const std::string& session_sid_cookie,
+ const std::string& session_lsid_cookie) {
+ fake_auth_code_ = auth_code;
+ fake_refresh_token_ = refresh_token;
+ fake_access_token_ = access_token;
+ fake_gaia_uber_token_ = gaia_uber_token;
+ fake_session_sid_cookie_ = session_sid_cookie;
+ fake_session_lsid_cookie_ = session_lsid_cookie;
+}
+
+void FakeGaia::Initialize() {
GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+ // Handles /ServiceLogin GAIA call.
+ REGISTER_RESPONSE_HANDLER(
+ gaia_urls->service_login_url(), HandleServiceLogin);
+
+ // Handles /ServiceLoginAuth GAIA call.
+ REGISTER_RESPONSE_HANDLER(
+ gaia_urls->service_login_auth_url(), HandleServiceLoginAuth);
+
+ // Handles /o/oauth2/programmatic_auth GAIA call.
+ REGISTER_RESPONSE_HANDLER(
+ gaia_urls->client_login_to_oauth2_url(), HandleProgramaticAuth);
+
+ // Handles /o/oauth2/token GAIA call.
+ REGISTER_RESPONSE_HANDLER(
+ gaia_urls->oauth2_token_url(), HandleAuthToken);
+
+ // Handles /OAuthLogin GAIA call.
+ REGISTER_RESPONSE_HANDLER(
+ gaia_urls->oauth1_login_url(), HandleOAuthLogin);
+
+ // Handles /MergeSession GAIA call.
+ REGISTER_RESPONSE_HANDLER(
+ gaia_urls->merge_session_url(), HandleMergeSession);
+
+ // Handles /oauth2/v2/IssueToken GAIA call.
+ REGISTER_RESPONSE_HANDLER(
+ gaia_urls->oauth2_issue_token_url(), HandleIssueToken);
+
+ // Handles /oauth2/v2/tokeninfo GAIA call.
+ REGISTER_RESPONSE_HANDLER(
+ gaia_urls->oauth2_token_info_url(), HandleTokenInfo);
+
+ // Handles /SSO GAIA call (not GAIA, made up for SAML tests).
+ REGISTER_PATH_RESPONSE_HANDLER("/SSO", HandleSSO);
+}
+
+void FakeGaia::HandleProgramaticAuth(
+ const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+ std::string scope;
+ if (!GetQueryParameter(request.content, "scope", &scope) ||
+ gaia_urls->oauth1_login_scope() != scope) {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ return;
+ }
+
+ std::string client_id;
+ if (!GetQueryParameter(request.content, "client_id", &client_id) ||
+ gaia_urls->oauth2_chrome_client_id() != client_id) {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ return;
+ }
+
+ http_response->AddCustomHeader(
+ "Set-Cookie",
+ base::StringPrintf(
+ "oauth_code=%s; Path=/o/GetOAuth2Token; Secure; HttpOnly;",
+ fake_auth_code_.c_str()));
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content_type("text/html");
+}
+
+void FakeGaia::HandleServiceLogin(const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content(service_login_response_);
+ http_response->set_content_type("text/html");
+}
+
+void FakeGaia::HandleOAuthLogin(const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ std::string access_token;
+ if (!GetAccessToken(request, kAuthHeaderOAuth, &access_token)) {
+ LOG(ERROR) << "/OAuthLogin missing access token in the header";
+ return;
+ }
- // 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();
+ std::string request_query = request_url.query();
- scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
- if (request_path == gaia_urls->service_login_url().path()) {
+ std::string source;
+ if (!GetQueryParameter(request_query, "source", &source)) {
+ LOG(ERROR) << "Missing 'source' param in /OAuthLogin call";
+ return;
+ }
+
+ std::string issue_uberauth;
+ if (GetQueryParameter(request_query, "issueuberauth", &issue_uberauth) &&
+ issue_uberauth == "1") {
+ http_response->set_content(fake_gaia_uber_token_);
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);
- std::string redirect_url = continue_url;
-
- std::string email;
- if (GetQueryParameter(request.content, "Email", &email) &&
- saml_account_idp_map_.find(email) != saml_account_idp_map_.end()) {
- GURL url(saml_account_idp_map_[email]);
- url = net::AppendQueryParameter(url, "SAMLRequest", "fake_request");
- url = net::AppendQueryParameter(url, "RelayState", continue_url);
- redirect_url = url.spec();
- }
+ // Issue GAIA uber token.
+ } else {
+ LOG(FATAL) << "/OAuthLogin for SID/LSID is not supported";
+ }
+}
+
+void FakeGaia::HandleMergeSession(const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+
+ std::string uber_token;
+ if (!GetQueryParameter(request.content, "uberauth", &uber_token) ||
+ uber_token != fake_gaia_uber_token_) {
+ LOG(ERROR) << "Missing or invalid 'uberauth' param in /MergeSession call";
+ return;
+ }
+
+ std::string continue_url;
+ if (!GetQueryParameter(request.content, "continue", &continue_url)) {
+ LOG(ERROR) << "Missing or invalid 'continue' param in /MergeSession call";
+ return;
+ }
+
+ std::string source;
+ if (!GetQueryParameter(request.content, "source", &source)) {
+ LOG(ERROR) << "Missing or invalid 'source' param in /MergeSession call";
+ return;
+ }
+
+ http_response->AddCustomHeader(
+ "Set-Cookie",
+ base::StringPrintf(
+ "SID=%s; LSID=%s; Path=/; Secure; HttpOnly;",
+ fake_session_sid_cookie_.c_str(),
+ fake_session_lsid_cookie_.c_str()));
+ // TODO(zelidrag): Not used now.
+ http_response->set_content("OK");
+ http_response->set_code(net::HTTP_OK);
+}
+
+
+void FakeGaia::HandleServiceLoginAuth(const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ std::string continue_url =
+ GaiaUrls::GetInstance()->service_login_url().spec();
+ GetQueryParameter(request.content, "continue", &continue_url);
+
+ std::string redirect_url = continue_url;
+
+ std::string email;
+ if (GetQueryParameter(request.content, "Email", &email) &&
+ saml_account_idp_map_.find(email) != saml_account_idp_map_.end()) {
+ GURL url(saml_account_idp_map_[email]);
+ url = net::AppendQueryParameter(url, "SAMLRequest", "fake_request");
+ url = net::AppendQueryParameter(url, "RelayState", continue_url);
+ redirect_url = url.spec();
+ }
+
+ http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
+ http_response->AddCustomHeader("Location", redirect_url);
+}
+
+void FakeGaia::HandleSSO(const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ std::string relay_state;
+ GetQueryParameter(request.content, "RelayState", &relay_state);
+ std::string redirect_url = relay_state;
+ http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
+ http_response->AddCustomHeader("Location", redirect_url);
+}
+
+void FakeGaia::HandleAuthToken(const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ std::string grant_type;
+ std::string refresh_token;
+ std::string client_id;
+ std::string scope;
+ std::string auth_code;
+ const AccessTokenInfo* token_info = NULL;
+ GetQueryParameter(request.content, "scope", &scope);
- http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
- http_response->AddCustomHeader("Location", redirect_url);
- } else if (request_path == gaia_urls->oauth2_token_url().path()) {
- std::string refresh_token;
- std::string client_id;
- std::string scope;
- const AccessTokenInfo* token_info = NULL;
- GetQueryParameter(request.content, "scope", &scope);
- if (GetQueryParameter(request.content, "refresh_token", &refresh_token) &&
- GetQueryParameter(request.content, "client_id", &client_id) &&
- (token_info = GetAccessTokenInfo(refresh_token, client_id, scope))) {
- 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 {
+ if (!GetQueryParameter(request.content, "grant_type", &grant_type)) {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ LOG(ERROR) << "No 'grant_type' param in /o/oauth2/token";
+ return;
+ }
+
+ if (grant_type == "authorization_code") {
+ if (!GetQueryParameter(request.content, "code", &auth_code) ||
+ auth_code != fake_auth_code_) {
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;
- }
- }
+ LOG(ERROR) << "No 'code' param in /o/oauth2/token";
+ return;
}
- 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 {
+ if (GaiaUrls::GetInstance()->oauth1_login_scope() != scope) {
http_response->set_code(net::HTTP_BAD_REQUEST);
- }
- } else if (request_path == gaia_urls->oauth2_issue_token_url().path()) {
- std::string access_token;
- std::map<std::string, std::string>::const_iterator auth_header_entry =
- request.headers.find("Authorization");
- if (auth_header_entry != request.headers.end()) {
- if (StartsWithASCII(auth_header_entry->second, "Bearer ", true))
- access_token = auth_header_entry->second.substr(7);
+ LOG(ERROR) << "Invalid scope for /o/oauth2/token - " << scope;
+ return;
}
- std::string scope;
- std::string client_id;
- const AccessTokenInfo* token_info = NULL;
- if (GetQueryParameter(request.content, "scope", &scope) &&
- GetQueryParameter(request.content, "client_id", &client_id) &&
- (token_info = GetAccessTokenInfo(access_token, client_id, scope))) {
- base::DictionaryValue response_dict;
- response_dict.SetString("issueAdvice", "auto");
- response_dict.SetString("expiresIn",
- base::IntToString(token_info->expires_in));
- response_dict.SetString("token", token_info->token);
- FormatJSONResponse(response_dict, http_response.get());
- } else {
- http_response->set_code(net::HTTP_BAD_REQUEST);
+ base::DictionaryValue response_dict;
+ response_dict.SetString("refresh_token", fake_refresh_token_);
+ response_dict.SetString("access_token", fake_access_token_);
+ response_dict.SetInteger("expires_in", 3600);
+ FormatJSONResponse(response_dict, http_response);
+ } else if (GetQueryParameter(request.content,
+ "refresh_token",
+ &refresh_token) &&
+ GetQueryParameter(request.content,
+ "client_id",
+ &client_id) &&
+ (token_info = FindAccessTokenInfo(refresh_token,
+ client_id,
+ scope))) {
+ base::DictionaryValue response_dict;
+ response_dict.SetString("access_token", token_info->token);
+ response_dict.SetInteger("expires_in", 3600);
+ FormatJSONResponse(response_dict, http_response);
+ } else {
+ LOG(ERROR) << "Bad request for /o/oauth2/token - "
+ << "refresh_token = " << refresh_token
+ << ", scope = " << scope
+ << ", client_id = " << client_id;
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ }
+}
+
+void FakeGaia::HandleTokenInfo(const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ 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;
+ }
}
- } else if (request_path == "/SSO") {
- std::string relay_state;
- GetQueryParameter(request.content, "RelayState", &relay_state);
- std::string redirect_url = relay_state;
- http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
- http_response->AddCustomHeader("Location", redirect_url);
+ }
+
+ 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);
+ } else {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ }
+}
+
+void FakeGaia::HandleIssueToken(const HttpRequest& request,
+ BasicHttpResponse* http_response) {
+ std::string access_token;
+ std::string scope;
+ std::string client_id;
+ const AccessTokenInfo* token_info = NULL;
+ if (GetAccessToken(request, kAuthHeaderBearer, &access_token) &&
+ GetQueryParameter(request.content, "scope", &scope) &&
+ GetQueryParameter(request.content, "client_id", &client_id) &&
+ (token_info = FindAccessTokenInfo(access_token, client_id, scope))) {
+ base::DictionaryValue response_dict;
+ response_dict.SetString("issueAdvice", "auto");
+ response_dict.SetString("expiresIn",
+ base::IntToString(token_info->expires_in));
+ response_dict.SetString("token", token_info->token);
+ FormatJSONResponse(response_dict, http_response);
+ } else {
+ http_response->set_code(net::HTTP_BAD_REQUEST);
+ }
+}
+
+
+scoped_ptr<HttpResponse> FakeGaia::HandleRequest(const HttpRequest& request) {
+ // 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());
+ RequestHandlerMap::iterator iter = request_handlers_.find(request_path);
+ if (iter != request_handlers_.end()) {
+ LOG(WARNING) << "Serving request " << request_path;
+ iter->second.Run(request, http_response.get());
} else {
- // Request not understood.
- return scoped_ptr<HttpResponse>();
+ LOG(ERROR) << "Unhandled request " << request_path;
+ return scoped_ptr<HttpResponse>(); // Request not understood.
}
return http_response.PassAs<HttpResponse>();
@@ -167,16 +381,6 @@ void FakeGaia::RegisterSamlUser(const std::string& account_id,
saml_account_idp_map_[account_id] = saml_idp;
}
-// 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);
-}
-
void FakeGaia::FormatJSONResponse(const base::DictionaryValue& response_dict,
BasicHttpResponse* http_response) {
std::string response_json;
@@ -185,7 +389,7 @@ void FakeGaia::FormatJSONResponse(const base::DictionaryValue& response_dict,
http_response->set_code(net::HTTP_OK);
}
-const FakeGaia::AccessTokenInfo* FakeGaia::GetAccessTokenInfo(
+const FakeGaia::AccessTokenInfo* FakeGaia::FindAccessTokenInfo(
const std::string& auth_token,
const std::string& client_id,
const std::string& scope_string) const {
@@ -208,3 +412,30 @@ const FakeGaia::AccessTokenInfo* FakeGaia::GetAccessTokenInfo(
return NULL;
}
+
+// 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);
+}
+
+// static
+bool FakeGaia::GetAccessToken(const HttpRequest& request,
+ const char* auth_token_prefix,
+ std::string* access_token) {
+ std::map<std::string, std::string>::const_iterator auth_header_entry =
+ request.headers.find("Authorization");
+ if (auth_header_entry != request.headers.end()) {
+ if (StartsWithASCII(auth_header_entry->second, auth_token_prefix, true)) {
+ *access_token = auth_header_entry->second.substr(
+ strlen(auth_token_prefix));
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/google_apis/gaia/fake_gaia.h b/google_apis/gaia/fake_gaia.h
index 7e211ae..6052c2b 100644
--- a/google_apis/gaia/fake_gaia.h
+++ b/google_apis/gaia/fake_gaia.h
@@ -10,6 +10,7 @@
#include <string>
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "url/gurl.h"
@@ -49,6 +50,18 @@ class FakeGaia {
FakeGaia();
~FakeGaia();
+ // Sets the initial value of tokens and cookies.
+ void SetAuthTokens(const std::string& auth_code,
+ const std::string& refresh_token,
+ const std::string& access_token,
+ const std::string& gaia_uber_token,
+ const std::string& session_sid_cookie,
+ const std::string& session_lsid_cookie);
+
+ // Initializes HTTP request handlers. Should be called after switches
+ // for tweaking GaiaUrls are in place.
+ void Initialize();
+
// 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().
@@ -81,16 +94,61 @@ class FakeGaia {
void FormatJSONResponse(const base::DictionaryValue& response_dict,
net::test_server::BasicHttpResponse* http_response);
+ typedef base::Callback<void(
+ const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response)>
+ HttpRequestHandlerCallback;
+ typedef std::map<std::string, HttpRequestHandlerCallback> RequestHandlerMap;
+
+ // HTTP request handlers.
+ void HandleProgramaticAuth(
+ const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+ void HandleServiceLogin(const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+ void HandleOAuthLogin(const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+ void HandleSSO(const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+ void HandleMergeSession(const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+ void HandleServiceLoginAuth(
+ const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+ void HandleAuthToken(const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+ void HandleTokenInfo(const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+ void HandleIssueToken(const net::test_server::HttpRequest& request,
+ net::test_server::BasicHttpResponse* http_response);
+
// Returns the access token associated with |auth_token| that matches the
// given |client_id| and |scope_string|. If |scope_string| is empty, the first
// token satisfying the other criteria is returned. Returns NULL if no token
// matches.
- const AccessTokenInfo* GetAccessTokenInfo(const std::string& auth_token,
- const std::string& client_id,
- const std::string& scope_string)
+ const AccessTokenInfo* FindAccessTokenInfo(const std::string& auth_token,
+ const std::string& client_id,
+ const std::string& scope_string)
const;
+ // Extracts the |access_token| from authorization header of |request|.
+ static bool GetAccessToken(const net::test_server::HttpRequest& request,
+ const char* auth_token_prefix,
+ std::string* access_token);
+
+ // auth_code cookie value response for /o/oauth2/programmatic_auth call.
+ std::string fake_auth_code_;
+
+ // refresh_token field value response for the initial /o/oauth2/token call
+ // with ...&grant_type=authorization_code.
+ std::string fake_refresh_token_;
+ std::string fake_access_token_;
+ std::string fake_gaia_uber_token_;
+ std::string fake_session_sid_cookie_;
+ std::string fake_session_lsid_cookie_;
+
AccessTokenInfoMap access_token_info_map_;
+ RequestHandlerMap request_handlers_;
std::string service_login_response_;
SamlAccountIdpMap saml_account_idp_map_;