login_utils.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/chromeos/login/login_utils.h" 6 7#include "base/command_line.h" 8#include "base/file_path.h" 9#include "base/file_util.h" 10#include "base/lock.h" 11#include "base/nss_util.h" 12#include "base/path_service.h" 13#include "base/scoped_ptr.h" 14#include "base/singleton.h" 15#include "base/time.h" 16#include "chrome/browser/browser_init.h" 17#include "chrome/browser/browser_process.h" 18#include "chrome/browser/chrome_thread.h" 19#include "chrome/browser/chromeos/cros/login_library.h" 20#include "chrome/browser/chromeos/cros/network_library.h" 21#include "chrome/browser/chromeos/external_cookie_handler.h" 22#include "chrome/browser/chromeos/login/cookie_fetcher.h" 23#include "chrome/browser/chromeos/login/google_authenticator.h" 24#include "chrome/browser/chromeos/login/user_image_downloader.h" 25#include "chrome/browser/chromeos/login/user_manager.h" 26#include "chrome/browser/net/gaia/token_service.h" 27#include "chrome/browser/profile.h" 28#include "chrome/browser/profile_manager.h" 29#include "chrome/common/logging_chrome.h" 30#include "chrome/common/chrome_paths.h" 31#include "chrome/common/chrome_switches.h" 32#include "chrome/common/net/url_request_context_getter.h" 33#include "chrome/common/notification_observer.h" 34#include "chrome/common/notification_registrar.h" 35#include "chrome/common/notification_service.h" 36#include "chrome/common/notification_type.h" 37#include "googleurl/src/gurl.h" 38#include "net/base/cookie_store.h" 39#include "net/url_request/url_request_context.h" 40#include "views/widget/widget_gtk.h" 41 42namespace chromeos { 43 44namespace { 45 46static char kIncognitoUser[] = "incognito"; 47 48// Prefix for Auth token received from ClientLogin request. 49const char kAuthPrefix[] = "Auth="; 50// Suffix for Auth token received from ClientLogin request. 51const char kAuthSuffix[] = "\n"; 52 53} // namespace 54 55class LoginUtilsImpl : public LoginUtils, 56 public NotificationObserver { 57 public: 58 LoginUtilsImpl() 59 : browser_launch_enabled_(true) { 60 registrar_.Add( 61 this, 62 NotificationType::LOGIN_USER_CHANGED, 63 NotificationService::AllSources()); 64 } 65 66 // Invoked after the user has successfully logged in. This launches a browser 67 // and does other bookkeeping after logging in. 68 virtual void CompleteLogin(const std::string& username, 69 const GaiaAuthConsumer::ClientLoginResult& credentials); 70 71 // Invoked after the tmpfs is successfully mounted. 72 // Launches a browser in the off the record (incognito) mode. 73 virtual void CompleteOffTheRecordLogin(); 74 75 // Creates and returns the authenticator to use. The caller owns the returned 76 // Authenticator and must delete it when done. 77 virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer); 78 79 // Used to postpone browser launch via DoBrowserLaunch() if some post 80 // login screen is to be shown. 81 virtual void EnableBrowserLaunch(bool enable); 82 83 // Returns if browser launch enabled now or not. 84 virtual bool IsBrowserLaunchEnabled() const; 85 86 // Returns auth token for 'cp' Contacts service. 87 virtual const std::string& GetAuthToken() const { return auth_token_; } 88 89 // NotificationObserver implementation. 90 virtual void Observe(NotificationType type, 91 const NotificationSource& source, 92 const NotificationDetails& details); 93 94 private: 95 // Attempt to connect to the preferred network if available. 96 void ConnectToPreferredNetwork(); 97 98 NotificationRegistrar registrar_; 99 100 // Indicates if DoBrowserLaunch will actually launch the browser or not. 101 bool browser_launch_enabled_; 102 103 // Auth token for Contacts service. Received by GoogleAuthenticator as 104 // part of ClientLogin response. 105 std::string auth_token_; 106 107 DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl); 108}; 109 110class LoginUtilsWrapper { 111 public: 112 LoginUtilsWrapper() {} 113 114 LoginUtils* get() { 115 AutoLock create(create_lock_); 116 if (!ptr_.get()) 117 reset(new LoginUtilsImpl); 118 return ptr_.get(); 119 } 120 121 void reset(LoginUtils* ptr) { 122 ptr_.reset(ptr); 123 } 124 125 private: 126 Lock create_lock_; 127 scoped_ptr<LoginUtils> ptr_; 128 129 DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper); 130}; 131 132void LoginUtilsImpl::CompleteLogin(const std::string& username, 133 const GaiaAuthConsumer::ClientLoginResult& credentials) { 134 135 LOG(INFO) << "Completing login for " << username; 136 137 if (CrosLibrary::Get()->EnsureLoaded()) 138 CrosLibrary::Get()->GetLoginLibrary()->StartSession(username, ""); 139 140 UserManager::Get()->UserLoggedIn(username); 141 ConnectToPreferredNetwork(); 142 143 // Now launch the initial browser window. 144 FilePath user_data_dir; 145 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 146 ProfileManager* profile_manager = g_browser_process->profile_manager(); 147 // The default profile will have been changed because the ProfileManager 148 // will process the notification that the UserManager sends out. 149 Profile* profile = profile_manager->GetDefaultProfile(user_data_dir); 150 151 logging::RedirectChromeLogging( 152 user_data_dir.Append(profile_manager->GetCurrentProfileDir()), 153 *(CommandLine::ForCurrentProcess()), 154 logging::DELETE_OLD_LOG_FILE); 155 156 // Supply credentials for sync and others to use 157 profile->GetTokenService()->SetClientLoginResult(credentials); 158 159 // Take the credentials passed in and try to exchange them for 160 // full-fledged Google authentication cookies. This is 161 // best-effort; it's possible that we'll fail due to network 162 // troubles or some such. Either way, |cf| will call 163 // DoBrowserLaunch on the UI thread when it's done, and then 164 // delete itself. 165 CookieFetcher* cf = new CookieFetcher(profile); 166 cf->AttemptFetch(credentials.data); 167 auth_token_ = credentials.token; 168} 169 170void LoginUtilsImpl::CompleteOffTheRecordLogin() { 171 LOG(INFO) << "Completing off the record login"; 172 173 if (CrosLibrary::Get()->EnsureLoaded()) 174 CrosLibrary::Get()->GetLoginLibrary()->StartSession(kIncognitoUser, ""); 175 176 // Incognito flag is not set by default. 177 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kIncognito); 178 179 UserManager::Get()->OffTheRecordUserLoggedIn(); 180 ConnectToPreferredNetwork(); 181 LoginUtils::DoBrowserLaunch( 182 ProfileManager::GetDefaultProfile()->GetOffTheRecordProfile()); 183} 184 185Authenticator* LoginUtilsImpl::CreateAuthenticator( 186 LoginStatusConsumer* consumer) { 187 return new GoogleAuthenticator(consumer); 188} 189 190void LoginUtilsImpl::EnableBrowserLaunch(bool enable) { 191 browser_launch_enabled_ = enable; 192} 193 194bool LoginUtilsImpl::IsBrowserLaunchEnabled() const { 195 return browser_launch_enabled_; 196} 197 198void LoginUtilsImpl::Observe(NotificationType type, 199 const NotificationSource& source, 200 const NotificationDetails& details) { 201 if (type == NotificationType::LOGIN_USER_CHANGED) 202 base::OpenPersistentNSSDB(); 203} 204 205void LoginUtilsImpl::ConnectToPreferredNetwork() { 206 CrosLibrary::Get()->GetNetworkLibrary()-> 207 ConnectToPreferredNetworkIfAvailable(); 208} 209 210LoginUtils* LoginUtils::Get() { 211 return Singleton<LoginUtilsWrapper>::get()->get(); 212} 213 214void LoginUtils::Set(LoginUtils* mock) { 215 Singleton<LoginUtilsWrapper>::get()->reset(mock); 216} 217 218void LoginUtils::DoBrowserLaunch(Profile* profile) { 219 // Browser launch was disabled due to some post login screen. 220 if (!LoginUtils::Get()->IsBrowserLaunchEnabled()) 221 return; 222 223 // Update command line in case loose values were added. 224 CommandLine::ForCurrentProcess()->InitFromArgv( 225 CommandLine::ForCurrentProcess()->argv()); 226 227 LOG(INFO) << "Launching browser..."; 228 BrowserInit browser_init; 229 int return_code; 230 browser_init.LaunchBrowser(*CommandLine::ForCurrentProcess(), 231 profile, 232 std::wstring(), 233 true, 234 &return_code); 235} 236 237std::string LoginUtils::ExtractClientLoginParam( 238 const std::string& credentials, 239 const std::string& param_prefix, 240 const std::string& param_suffix) { 241 size_t start = credentials.find(param_prefix); 242 if (start == std::string::npos) 243 return std::string(); 244 start += param_prefix.size(); 245 size_t end = credentials.find(param_suffix, start); 246 if (end == std::string::npos) 247 return std::string(); 248 return credentials.substr(start, end - start); 249} 250 251} // namespace chromeos 252