Refactor the authenticate-with-google code to prep for doing it inside chrome
Review URL: http://codereview.chromium.org/650097
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39641 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/chromeos/login/authenticator.h b/chrome/browser/chromeos/login/authenticator.h
new file mode 100644
index 0000000..d03be58
--- /dev/null
+++ b/chrome/browser/chromeos/login/authenticator.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2010 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_AUTHENTICATOR_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_AUTHENTICATOR_H_
+
+#include "base/logging.h"
+#include "chrome/browser/chromeos/login/login_status_consumer.h"
+
+// An interface for objects that will authenticate a Chromium OS user.
+// When authentication successfully completes, will call
+// consumer_->OnLoginSuccess(|username|).
+// On failure, will call consumer_->OnLoginFailure().
+
+class Authenticator {
+ public:
+ explicit Authenticator(LoginStatusConsumer* consumer)
+ : consumer_(consumer) {
+ }
+ virtual ~Authenticator() {}
+
+ // Given a |username| and |password|, this method attempts to authenticate
+ // Returns true if we kick off the attempt successfully and false if we can't.
+ virtual bool Authenticate(const std::string& username,
+ const std::string& password) = 0;
+
+ protected:
+ LoginStatusConsumer* consumer_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Authenticator);
+};
+
+class StubAuthenticator : public Authenticator {
+ public:
+ explicit StubAuthenticator(LoginStatusConsumer* consumer)
+ : Authenticator(consumer) {
+ }
+ virtual ~StubAuthenticator() {}
+
+ // Returns true after calling OnLoginSuccess().
+ virtual bool Authenticate(const std::string& username,
+ const std::string& password) {
+ consumer_->OnLoginSuccess(username);
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StubAuthenticator);
+};
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_AUTHENTICATOR_H_
diff --git a/chrome/browser/chromeos/login/google_authenticator.cc b/chrome/browser/chromeos/login/google_authenticator.cc
new file mode 100644
index 0000000..9bd5a30
--- /dev/null
+++ b/chrome/browser/chromeos/login/google_authenticator.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2010 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 <string>
+
+#include "base/logging.h"
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/login/google_authenticator.h"
+#include "chrome/browser/chromeos/login/login_status_consumer.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/net/url_fetcher.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/profile_manager.h"
+#include "chrome/common/chrome_paths.h"
+#include "net/base/load_flags.h"
+#include "third_party/libjingle/files/talk/base/urlencode.h"
+
+const char GoogleAuthenticator::kClientLoginUrl[] =
+ "https://www.google.com/accounts/ClientLogin";
+const char GoogleAuthenticator::kFormat[] =
+ "Email=%s&"
+ "Passwd=%s&"
+ "PersistentCookie=%s&"
+ "accountType=%s&"
+ "source=%s&";
+const char GoogleAuthenticator::kCookiePersistence[] = "true";
+const char GoogleAuthenticator::kAccountType[] = "HOSTED_OR_GOOGLE";
+const char GoogleAuthenticator::kSource[] = "chromeos";
+
+bool GoogleAuthenticator::Authenticate(const std::string& username,
+ const std::string& password) {
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
+ URLRequestContextGetter *getter =
+ profile->GetOffTheRecordProfile()->GetRequestContext();
+ fetcher_.reset(new URLFetcher(GURL(kClientLoginUrl),
+ URLFetcher::POST,
+ this));
+ fetcher_->set_request_context(getter);
+ fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES);
+ // TODO(cmasone): be more careful about zeroing memory that stores
+ // the user's password.
+ std::string body = StringPrintf(kFormat,
+ UrlEncodeString(username).c_str(),
+ UrlEncodeString(password).c_str(),
+ kCookiePersistence,
+ kAccountType,
+ kSource);
+ fetcher_->set_upload_data("application/x-www-form-urlencoded", body);
+ fetcher_->Start();
+ username_.assign(username);
+ return true;
+}
+
+void GoogleAuthenticator::OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ // TODO(cmasone):
+ // If successful, post a task to the UI thread with the cookies.
+ // That task will mount cryptohome (has to be on the UI thread, as
+ // it talks to dbus...eww) and then tell the UserManager that the
+ // user logged in, get the new profile, and then inject cookies.
+ // Then, do all the BrowserInit stuff.
+
+ LOG(INFO) << "ClientLogin response code: " << response_code;
+ if (200 == response_code) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(
+ GoogleAuthenticator::OnLoginSuccess, consumer_, username_));
+ } else {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(GoogleAuthenticator::OnLoginFailure, consumer_));
+ }
+}
+
+// static
+void GoogleAuthenticator::OnLoginSuccess(LoginStatusConsumer* consumer,
+ const std::string& username) {
+ consumer->OnLoginSuccess(username);
+}
+
+// static
+void GoogleAuthenticator::OnLoginFailure(LoginStatusConsumer* consumer) {
+ consumer->OnLoginFailure();
+}
diff --git a/chrome/browser/chromeos/login/google_authenticator.h b/chrome/browser/chromeos/login/google_authenticator.h
new file mode 100644
index 0000000..b4da66a
--- /dev/null
+++ b/chrome/browser/chromeos/login/google_authenticator.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 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_GOOGLE_AUTHENTICATOR_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_GOOGLE_AUTHENTICATOR_H_
+
+#include <string>
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/net/url_fetcher.h"
+
+class LoginStatusConsumer;
+
+// Authenticates a Chromium OS user against the Google Accounts ClientLogin API.
+
+class GoogleAuthenticator : public Authenticator,
+ public URLFetcher::Delegate {
+ public:
+ explicit GoogleAuthenticator(LoginStatusConsumer* consumer)
+ : Authenticator(consumer),
+ fetcher_(NULL) {
+ }
+ virtual ~GoogleAuthenticator() {}
+
+ // Given a |username| and |password|, this method attempts to authenticate to
+ // the Google accounts servers.
+ // Returns true if the attempt gets sent successfully and false if not.
+ bool Authenticate(const std::string& username,
+ const std::string& password);
+
+ // Overridden from URLFetcher::Delegate
+ // When the authentication attempt comes back, will call
+ // consumer_->OnLoginSuccess(|username|).
+ // On any failure, will call consumer_->OnLoginFailure().
+ virtual void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+
+ // I need these static methods so I can PostTasks that use methods
+ // of sublcasses of LoginStatusConsumer. I can't seem to make
+ // RunnableMethods out of methods belonging to subclasses without referring
+ // to the subclasses specifically, and I want to allow mocked out
+ // LoginStatusConsumers to be used here as well.
+ static void OnLoginSuccess(LoginStatusConsumer* consumer,
+ const std::string& username);
+ static void OnLoginFailure(LoginStatusConsumer* consumer);
+
+ private:
+ static const char kCookiePersistence[];
+ static const char kAccountType[];
+ static const char kSource[];
+ static const char kClientLoginUrl[];
+ static const char kFormat[];
+
+ scoped_ptr<URLFetcher> fetcher_;
+ std::string username_;
+ DISALLOW_COPY_AND_ASSIGN(GoogleAuthenticator);
+};
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_GOOGLE_AUTHENTICATOR_H_
diff --git a/chrome/browser/chromeos/login/login_manager_view.cc b/chrome/browser/chromeos/login/login_manager_view.cc
index 3e95c2c..c0b0582 100644
--- a/chrome/browser/chromeos/login/login_manager_view.cc
+++ b/chrome/browser/chromeos/login/login_manager_view.cc
@@ -22,6 +22,8 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/chromeos/login/google_authenticator.h"
+#include "chrome/browser/chromeos/login/pam_google_authenticator.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
#include "chrome/browser/chromeos/login/user_manager.h"
@@ -78,7 +80,13 @@
observer_(observer),
error_id_(-1),
ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)),
- focus_delayed_(false) {
+ focus_delayed_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ authenticator_(new PamGoogleAuthenticator(this))) {
+ if (kStubOutLogin)
+ authenticator_.reset(new StubAuthenticator(this));
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kInChromeAuth))
+ authenticator_.reset(new GoogleAuthenticator(this));
}
LoginManagerView::~LoginManagerView() {
@@ -269,25 +277,42 @@
Login();
}
-bool LoginManagerView::Authenticate(const std::string& username,
- const std::string& password) {
- if (kStubOutLogin) {
- return true;
- }
+void LoginManagerView::OnLoginFailure() {
+ LOG(INFO) << "LoginManagerView: OnLoginFailure()";
+ chromeos::NetworkLibrary* network = chromeos::NetworkLibrary::Get();
+ // Check networking after trying to login in case user is
+ // cached locally or the local admin account.
+ if (!network || !network->EnsureLoaded())
+ ShowError(IDS_LOGIN_ERROR_NO_NETWORK_LIBRARY);
+ else if (!network->Connected())
+ ShowError(IDS_LOGIN_ERROR_NETWORK_NOT_CONNECTED);
+ else
+ ShowError(IDS_LOGIN_ERROR_AUTHENTICATING);
+}
- base::ProcessHandle handle;
- std::vector<std::string> argv;
- // TODO(cmasone): we'll want this to be configurable.
- argv.push_back("/opt/google/chrome/session");
- argv.push_back(username);
- argv.push_back(password);
+void LoginManagerView::OnLoginSuccess(const std::string& username) {
+ LOG(INFO) << "LoginManagerView: OnLoginSuccess()";
+ // TODO(cmasone): something sensible if errors occur.
+ SetupSession(username);
+ chromeos::UserManager::Get()->UserLoggedIn(username);
- base::environment_vector no_env;
- base::file_handle_mapping_vector no_files;
- base::LaunchApp(argv, no_env, no_files, false, &handle);
- int child_exit_code;
- return base::WaitForExitCode(handle, &child_exit_code) &&
- child_exit_code == 0;
+ // Now launch the initial browser window.
+ BrowserInit browser_init;
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ // The default profile will have been changed because the ProfileManager
+ // will process the notification that the UserManager sends out.
+ Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
+ int return_code;
+
+ LOG(INFO) << "OnLoginSuccess: Preparing to launch browser";
+ browser_init.LaunchBrowser(command_line,
+ profile,
+ std::wstring(),
+ true,
+ &return_code);
}
void LoginManagerView::SetupSession(const std::string& username) {
@@ -320,40 +345,7 @@
username_field_->SetText(UTF8ToUTF16(username));
}
- // Set up credentials to prepare for authentication.
- if (Authenticate(username, password)) {
- // TODO(cmasone): something sensible if errors occur.
- SetupSession(username);
- chromeos::UserManager::Get()->UserLoggedIn(username);
-
- // Now launch the initial browser window.
- BrowserInit browser_init;
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- FilePath user_data_dir;
- PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
- ProfileManager* profile_manager = g_browser_process->profile_manager();
- // The default profile will have been changed because the ProfileManager
- // will process the notification that the UserManager sends out.
- Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
- int return_code;
-
- browser_init.LaunchBrowser(
- command_line,
- profile,
- std::wstring(),
- true,
- &return_code);
- } else {
- chromeos::NetworkLibrary* network = chromeos::NetworkLibrary::Get();
- // Check networking after trying to login in case user is
- // cached locally or the local admin account.
- if (!network || !network->EnsureLoaded())
- ShowError(IDS_LOGIN_ERROR_NO_NETWORK_LIBRARY);
- else if (!network->Connected())
- ShowError(IDS_LOGIN_ERROR_NETWORK_NOT_CONNECTED);
- else
- ShowError(IDS_LOGIN_ERROR_AUTHENTICATING);
- }
+ authenticator_->Authenticate(username, password);
}
void LoginManagerView::ShowError(int error_id) {
diff --git a/chrome/browser/chromeos/login/login_manager_view.h b/chrome/browser/chromeos/login/login_manager_view.h
index cc9e6fa..b387af5 100644
--- a/chrome/browser/chromeos/login/login_manager_view.h
+++ b/chrome/browser/chromeos/login/login_manager_view.h
@@ -6,7 +6,9 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_MANAGER_VIEW_H_
#include <string>
-#include "base/task.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/wizard_screen.h"
#include "chrome/browser/chromeos/version_loader.h"
#include "views/accelerator.h"
@@ -24,7 +26,8 @@
class NativeButton;
} // namespace views
-class LoginManagerView : public WizardScreen,
+class LoginManagerView : public LoginStatusConsumer,
+ public WizardScreen,
public views::WindowDelegate,
public views::Textfield::Controller,
public views::ButtonListener {
@@ -54,6 +57,10 @@
// Overriden from views::ButtonListener.
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+ // Overriden from LoginStatusConsumer.
+ virtual void OnLoginFailure();
+ virtual void OnLoginSuccess(const std::string& username);
+
protected:
// views::View overrides:
virtual void ViewHierarchyChanged(bool is_add, views::View *parent,
@@ -119,6 +126,8 @@
// (on the hidden tab, for example).
bool focus_delayed_;
+ scoped_ptr<Authenticator> authenticator_;
+
DISALLOW_COPY_AND_ASSIGN(LoginManagerView);
};
diff --git a/chrome/browser/chromeos/login/login_status_consumer.h b/chrome/browser/chromeos/login/login_status_consumer.h
new file mode 100644
index 0000000..0b2a658
--- /dev/null
+++ b/chrome/browser/chromeos/login/login_status_consumer.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2010 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_LOGIN_STATUS_CONSUMER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_STATUS_CONSUMER_H_
+
+#include <string>
+
+// An interface that defines the callbacks for objects that the
+// Authenticator class will call to report the success/failure of
+// authentication for Chromium OS.
+class LoginStatusConsumer {
+ public:
+ virtual ~LoginStatusConsumer() {}
+ virtual void OnLoginFailure() = 0;
+ virtual void OnLoginSuccess(const std::string& username) = 0;
+};
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_STATUS_CONSUMER_H_
diff --git a/chrome/browser/chromeos/login/pam_google_authenticator.cc b/chrome/browser/chromeos/login/pam_google_authenticator.cc
new file mode 100644
index 0000000..fd32c2a
--- /dev/null
+++ b/chrome/browser/chromeos/login/pam_google_authenticator.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2010 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 <string>
+
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "chrome/browser/chromeos/login/pam_google_authenticator.h"
+#include "chrome/browser/chromeos/login/login_status_consumer.h"
+
+bool PamGoogleAuthenticator::Authenticate(const std::string& username,
+ const std::string& password) {
+ base::ProcessHandle handle;
+ std::vector<std::string> argv;
+ // TODO(cmasone): we'll want this to be configurable.
+ argv.push_back("/opt/google/chrome/session");
+ argv.push_back(username);
+ argv.push_back(password);
+
+ base::environment_vector no_env;
+ base::file_handle_mapping_vector no_files;
+ base::LaunchApp(argv, no_env, no_files, false, &handle);
+ int child_exit_code;
+ bool ret = (base::WaitForExitCode(handle, &child_exit_code) &&
+ child_exit_code == 0);
+
+ if (ret)
+ consumer_->OnLoginSuccess(username);
+ else
+ consumer_->OnLoginFailure();
+ return ret;
+}
diff --git a/chrome/browser/chromeos/login/pam_google_authenticator.h b/chrome/browser/chromeos/login/pam_google_authenticator.h
new file mode 100644
index 0000000..688f0c3
--- /dev/null
+++ b/chrome/browser/chromeos/login/pam_google_authenticator.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 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_PAM_GOOGLE_AUTHENTICATOR_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_PAM_GOOGLE_AUTHENTICATOR_H_
+
+#include <string>
+#include "chrome/browser/chromeos/login/authenticator.h"
+
+class LoginStatusConsumer;
+
+// Authenticates a Chromium OS user against the Google Accounts ClientLogin API.
+
+class PamGoogleAuthenticator : public Authenticator {
+ public:
+ explicit PamGoogleAuthenticator(LoginStatusConsumer* consumer)
+ : Authenticator(consumer) {
+ }
+ virtual ~PamGoogleAuthenticator() {}
+
+ // Given a |username| and |password|, this method attempts to authenticate to
+ // the Google accounts servers.
+ // Returns true if the attempt gets sent successfully and false if not.
+ bool Authenticate(const std::string& username,
+ const std::string& password);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PamGoogleAuthenticator);
+};
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_PAM_GOOGLE_AUTHENTICATOR_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 270667a..3d97e3b 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -319,10 +319,16 @@
'browser/chromeos/gview_request_interceptor.h',
'browser/chromeos/login/account_creation_view.cc',
'browser/chromeos/login/account_creation_view.h',
+ 'browser/chromeos/login/authenticator.h',
+ 'browser/chromeos/login/google_authenticator.cc',
+ 'browser/chromeos/login/google_authenticator.h',
'browser/chromeos/login/image_background.h',
'browser/chromeos/login/ipc_message.h',
+ 'browser/chromeos/login/pam_google_authenticator.cc',
+ 'browser/chromeos/login/pam_google_authenticator.h',
'browser/chromeos/login/login_manager_view.cc',
'browser/chromeos/login/login_manager_view.h',
+ 'browser/chromeos/login/login_status_consumer.h',
'browser/chromeos/login/login_wizard_view.cc',
'browser/chromeos/login/login_wizard_view.h',
'browser/chromeos/login/network_selection_view.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 9f18551..85fa07a 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -741,13 +741,14 @@
// Document Viewer.
const char kEnableGView[] = "enable-gview";
-// Enable experimental Chrome-as-a-login-manager behavior.
+// Enable Chrome-as-a-login-manager behavior.
const char kLoginManager[] = "login-manager";
+// Enable Chrome to do ClientLogin on its own in the login-manager context.
+const char kInChromeAuth[] = "in-chrome-auth";
// Enables to override the first login screen.
const char kFirstLoginScreenName[] = "first-login-screen-name";
// Allows control over the initial login screen size. Pass width,height.
const char kLoginScreenSize[] = "login-screen-size";
-const char kSessionManagerPipe[] = "session-manager-pipe";
// Attempts to load libcros and validate it, then exits. A nonzero return code
// means the library could not be loaded correctly.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 0785a565..5ec34b6 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -214,11 +214,11 @@
extern const char kCookiePipe[];
extern const char kEnableGView[];
extern const char kLoginManager[];
+extern const char kInChromeAuth[];
// TODO(avayvod): Remove this flag when it's unnecessary for testing
// purposes.
extern const char kFirstLoginScreenName[];
extern const char kLoginScreenSize[];
-extern const char kSessionManagerPipe[];
extern const char kTestLoadLibcros[];
extern const char kProfile[];
extern const char kLoginProfile[];