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