| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/login_prompt.h" | 5 #include "chrome/browser/login_prompt.h" |
| 6 | 6 |
| 7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "chrome/browser/chrome_thread.h" | 8 #include "chrome/browser/chrome_thread.h" |
| 9 #include "chrome/browser/password_manager/password_manager.h" | 9 #include "chrome/browser/password_manager/password_manager.h" |
| 10 #include "chrome/browser/renderer_host/render_process_host.h" | 10 #include "chrome/browser/renderer_host/render_process_host.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 using webkit_glue::PasswordForm; | 22 using webkit_glue::PasswordForm; |
| 23 | 23 |
| 24 // ---------------------------------------------------------------------------- | 24 // ---------------------------------------------------------------------------- |
| 25 // LoginHandlerWin | 25 // LoginHandlerWin |
| 26 | 26 |
| 27 // This class simply forwards the authentication from the LoginView (on | 27 // This class simply forwards the authentication from the LoginView (on |
| 28 // the UI thread) to the URLRequest (on the I/O thread). | 28 // the UI thread) to the URLRequest (on the I/O thread). |
| 29 // This class uses ref counting to ensure that it lives until all InvokeLaters | 29 // This class uses ref counting to ensure that it lives until all InvokeLaters |
| 30 // have been called. | 30 // have been called. |
| 31 class LoginHandlerWin : public LoginHandler, | 31 class LoginHandlerWin : public LoginHandler, |
| 32 public base::RefCountedThreadSafe<LoginHandlerWin>, | |
| 33 public views::DialogDelegate { | 32 public views::DialogDelegate { |
| 34 public: | 33 public: |
| 35 explicit LoginHandlerWin(URLRequest* request) | 34 explicit LoginHandlerWin(URLRequest* request) : LoginHandler(request) { |
| 36 : dialog_(NULL), | 35 } |
| 37 handled_auth_(false), | |
| 38 request_(request), | |
| 39 password_manager_(NULL) { | |
| 40 DCHECK(request_) << "LoginHandler constructed with NULL request"; | |
| 41 | 36 |
| 42 AddRef(); // matched by ReleaseLater. | 37 // LoginModelObserver implementation. |
| 43 if (!ResourceDispatcherHost::RenderViewForRequest(request_, | 38 virtual void OnAutofillDataAvailable(const std::wstring& username, |
| 44 &render_process_host_id_, | 39 const std::wstring& password) { |
| 45 &tab_contents_id_)) { | 40 // Nothing to do here since LoginView takes care of autofil for win. |
| 46 NOTREACHED(); | |
| 47 } | |
| 48 } | 41 } |
| 49 | 42 |
| 50 void set_login_view(LoginView* login_view) { | 43 void set_login_view(LoginView* login_view) { |
| 51 login_view_ = login_view; | 44 login_view_ = login_view; |
| 52 } | 45 } |
| 53 | 46 |
| 54 // views::DialogDelegate methods: | 47 // views::DialogDelegate methods: |
| 55 virtual std::wstring GetDialogButtonLabel( | 48 virtual std::wstring GetDialogButtonLabel( |
| 56 MessageBoxFlags::DialogButton button) const { | 49 MessageBoxFlags::DialogButton button) const { |
| 57 if (button == MessageBoxFlags::DIALOGBUTTON_OK) | 50 if (button == MessageBoxFlags::DIALOGBUTTON_OK) |
| 58 return l10n_util::GetString(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL); | 51 return l10n_util::GetString(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL); |
| 59 return DialogDelegate::GetDialogButtonLabel(button); | 52 return DialogDelegate::GetDialogButtonLabel(button); |
| 60 } | 53 } |
| 54 |
| 61 virtual std::wstring GetWindowTitle() const { | 55 virtual std::wstring GetWindowTitle() const { |
| 62 return l10n_util::GetString(IDS_LOGIN_DIALOG_TITLE); | 56 return l10n_util::GetString(IDS_LOGIN_DIALOG_TITLE); |
| 63 } | 57 } |
| 58 |
| 64 virtual void WindowClosing() { | 59 virtual void WindowClosing() { |
| 65 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 60 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 66 | 61 |
| 67 TabContents* tab = GetTabContentsForLogin(); | 62 TabContents* tab = GetTabContentsForLogin(); |
| 68 if (tab) | 63 if (tab) |
| 69 tab->render_view_host()->set_ignore_input_events(false); | 64 tab->render_view_host()->set_ignore_input_events(false); |
| 70 | 65 |
| 71 // Reference is no longer valid. | 66 // Reference is no longer valid. |
| 72 dialog_ = NULL; | 67 SetDialog(NULL); |
| 73 | 68 |
| 74 if (!WasAuthHandled(true)) { | 69 CancelAuth(); |
| 75 ChromeThread::PostTask( | |
| 76 ChromeThread::IO, FROM_HERE, | |
| 77 NewRunnableMethod(this, &LoginHandlerWin::CancelAuthDeferred)); | |
| 78 SendNotifications(); | |
| 79 } | |
| 80 } | 70 } |
| 71 |
| 81 virtual void DeleteDelegate() { | 72 virtual void DeleteDelegate() { |
| 82 // Delete this object once all InvokeLaters have been called. | 73 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 83 ChromeThread::ReleaseSoon(ChromeThread::IO, FROM_HERE, this); | 74 |
| 75 // The constrained window is going to delete itself; clear our pointer. |
| 76 SetDialog(NULL); |
| 77 SetModel(NULL); |
| 78 |
| 79 ReleaseSoon(); |
| 84 } | 80 } |
| 81 |
| 85 virtual bool Cancel() { | 82 virtual bool Cancel() { |
| 86 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 83 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 87 DCHECK(dialog_) << "LoginHandler invoked without being attached"; | 84 |
| 88 CancelAuth(); | 85 CancelAuth(); |
| 89 return true; | 86 return true; |
| 90 } | 87 } |
| 88 |
| 91 virtual bool Accept() { | 89 virtual bool Accept() { |
| 92 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 90 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 93 DCHECK(dialog_) << "LoginHandler invoked without being attached"; | 91 |
| 94 SetAuth(login_view_->GetUsername(), login_view_->GetPassword()); | 92 SetAuth(login_view_->GetUsername(), login_view_->GetPassword()); |
| 95 return true; | 93 return true; |
| 96 } | 94 } |
| 95 |
| 97 virtual views::View* GetContentsView() { | 96 virtual views::View* GetContentsView() { |
| 98 return login_view_; | 97 return login_view_; |
| 99 } | 98 } |
| 100 | 99 |
| 101 // LoginHandler: | 100 // LoginHandler: |
| 102 | 101 |
| 103 virtual void BuildViewForPasswordManager(PasswordManager* manager, | 102 virtual void BuildViewForPasswordManager(PasswordManager* manager, |
| 104 std::wstring explanation) { | 103 std::wstring explanation) { |
| 105 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 104 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 106 | 105 |
| 107 LoginView* view = new LoginView(explanation); | 106 LoginView* view = new LoginView(explanation); |
| 108 | 107 |
| 109 // Set the model for the login view. The model (password manager) is owned | 108 // Set the model for the login view. The model (password manager) is owned |
| 110 // by the view's parent TabContents, so natural destruction order means we | 109 // by the view's parent TabContents, so natural destruction order means we |
| 111 // don't have to worry about calling SetModel(NULL), because the view will | 110 // don't have to worry about calling SetModel(NULL), because the view will |
| 112 // be deleted before the password manager. | 111 // be deleted before the password manager. |
| 113 view->SetModel(manager); | 112 view->SetModel(manager); |
| 114 | 113 |
| 115 set_login_view(view); | 114 set_login_view(view); |
| 116 | 115 |
| 117 // Scary thread safety note: This can potentially be called *after* SetAuth | 116 // Scary thread safety note: This can potentially be called *after* SetAuth |
| 118 // or CancelAuth (say, if the request was cancelled before the UI thread got | 117 // or CancelAuth (say, if the request was cancelled before the UI thread got |
| 119 // control). However, that's OK since any UI interaction in those functions | 118 // control). However, that's OK since any UI interaction in those functions |
| 120 // will occur via an InvokeLater on the UI thread, which is guaranteed | 119 // will occur via an InvokeLater on the UI thread, which is guaranteed |
| 121 // to happen after this is called (since this was InvokeLater'd first). | 120 // to happen after this is called (since this was InvokeLater'd first). |
| 122 dialog_ = GetTabContentsForLogin()->CreateConstrainedDialog(this); | 121 SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this)); |
| 123 SendNotifications(); | 122 SendNotifications(); |
| 124 } | 123 } |
| 125 | 124 |
| 126 virtual void SetPasswordForm(const webkit_glue::PasswordForm& form) { | |
| 127 password_form_ = form; | |
| 128 } | |
| 129 | |
| 130 virtual void SetPasswordManager(PasswordManager* password_manager) { | |
| 131 password_manager_ = password_manager; | |
| 132 } | |
| 133 | |
| 134 virtual TabContents* GetTabContentsForLogin() { | |
| 135 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 136 | |
| 137 return tab_util::GetTabContentsByID(render_process_host_id_, | |
| 138 tab_contents_id_); | |
| 139 } | |
| 140 | |
| 141 virtual void SetAuth(const std::wstring& username, | |
| 142 const std::wstring& password) { | |
| 143 if (WasAuthHandled(true)) | |
| 144 return; | |
| 145 | |
| 146 // Tell the password manager the credentials were submitted / accepted. | |
| 147 if (password_manager_) { | |
| 148 password_form_.username_value = username; | |
| 149 password_form_.password_value = password; | |
| 150 password_manager_->ProvisionallySavePassword(password_form_); | |
| 151 } | |
| 152 | |
| 153 ChromeThread::PostTask( | |
| 154 ChromeThread::UI, FROM_HERE, | |
| 155 NewRunnableMethod(this, &LoginHandlerWin::CloseContentsDeferred)); | |
| 156 ChromeThread::PostTask( | |
| 157 ChromeThread::UI, FROM_HERE, | |
| 158 NewRunnableMethod(this, &LoginHandlerWin::SendNotifications)); | |
| 159 ChromeThread::PostTask( | |
| 160 ChromeThread::IO, FROM_HERE, | |
| 161 NewRunnableMethod( | |
| 162 this, &LoginHandlerWin::SetAuthDeferred, username, password)); | |
| 163 } | |
| 164 | |
| 165 virtual void CancelAuth() { | |
| 166 if (WasAuthHandled(true)) | |
| 167 return; | |
| 168 | |
| 169 ChromeThread::PostTask( | |
| 170 ChromeThread::UI, FROM_HERE, | |
| 171 NewRunnableMethod(this, &LoginHandlerWin::CloseContentsDeferred)); | |
| 172 ChromeThread::PostTask( | |
| 173 ChromeThread::UI, FROM_HERE, | |
| 174 NewRunnableMethod(this, &LoginHandlerWin::SendNotifications)); | |
| 175 ChromeThread::PostTask( | |
| 176 ChromeThread::IO, FROM_HERE, | |
| 177 NewRunnableMethod(this, &LoginHandlerWin::CancelAuthDeferred)); | |
| 178 } | |
| 179 | |
| 180 virtual void OnRequestCancelled() { | |
| 181 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) << | |
| 182 "Why is OnRequestCancelled called from the UI thread?"; | |
| 183 | |
| 184 // Reference is no longer valid. | |
| 185 request_ = NULL; | |
| 186 | |
| 187 // Give up on auth if the request was cancelled. | |
| 188 CancelAuth(); | |
| 189 } | |
| 190 | |
| 191 private: | 125 private: |
| 192 friend class base::RefCountedThreadSafe<LoginHandlerWin>; | 126 friend class base::RefCountedThreadSafe<LoginHandlerWin>; |
| 193 friend class LoginPrompt; | 127 friend class LoginPrompt; |
| 194 | 128 |
| 195 ~LoginHandlerWin() {} | 129 ~LoginHandlerWin() {} |
| 196 | 130 |
| 197 // Calls SetAuth from the IO loop. | |
| 198 void SetAuthDeferred(const std::wstring& username, | |
| 199 const std::wstring& password) { | |
| 200 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | |
| 201 | |
| 202 if (request_) { | |
| 203 request_->SetAuth(username, password); | |
| 204 ResetLoginHandlerForRequest(request_); | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 // Calls CancelAuth from the IO loop. | |
| 209 void CancelAuthDeferred() { | |
| 210 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | |
| 211 | |
| 212 if (request_) { | |
| 213 request_->CancelAuth(); | |
| 214 // Verify that CancelAuth does destroy the request via our delegate. | |
| 215 DCHECK(request_ != NULL); | |
| 216 ResetLoginHandlerForRequest(request_); | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 // Closes the view_contents from the UI loop. | |
| 221 void CloseContentsDeferred() { | |
| 222 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 223 | |
| 224 // The hosting ConstrainedWindow may have been freed. | |
| 225 if (dialog_) | |
| 226 dialog_->CloseConstrainedWindow(); | |
| 227 } | |
| 228 | |
| 229 // Returns whether authentication had been handled (SetAuth or CancelAuth). | |
| 230 // If |set_handled| is true, it will mark authentication as handled. | |
| 231 bool WasAuthHandled(bool set_handled) { | |
| 232 AutoLock lock(handled_auth_lock_); | |
| 233 bool was_handled = handled_auth_; | |
| 234 if (set_handled) | |
| 235 handled_auth_ = true; | |
| 236 return was_handled; | |
| 237 } | |
| 238 | |
| 239 // Notify observers that authentication is needed or received. The automation | |
| 240 // proxy uses this for testing. | |
| 241 void SendNotifications() { | |
| 242 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 243 | |
| 244 NotificationService* service = NotificationService::current(); | |
| 245 TabContents* requesting_contents = GetTabContentsForLogin(); | |
| 246 if (!requesting_contents) | |
| 247 return; | |
| 248 | |
| 249 NavigationController* controller = &requesting_contents->controller(); | |
| 250 | |
| 251 if (!WasAuthHandled(false)) { | |
| 252 LoginNotificationDetails details(this); | |
| 253 service->Notify(NotificationType::AUTH_NEEDED, | |
| 254 Source<NavigationController>(controller), | |
| 255 Details<LoginNotificationDetails>(&details)); | |
| 256 } else { | |
| 257 service->Notify(NotificationType::AUTH_SUPPLIED, | |
| 258 Source<NavigationController>(controller), | |
| 259 NotificationService::NoDetails()); | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 // True if we've handled auth (SetAuth or CancelAuth has been called). | |
| 264 bool handled_auth_; | |
| 265 Lock handled_auth_lock_; | |
| 266 | |
| 267 // The ConstrainedWindow that is hosting our LoginView. | |
| 268 // This should only be accessed on the UI loop. | |
| 269 ConstrainedWindow* dialog_; | |
| 270 | |
| 271 // The request that wants login data. | |
| 272 // This should only be accessed on the IO loop. | |
| 273 URLRequest* request_; | |
| 274 | |
| 275 // The LoginView that contains the user's login information | 131 // The LoginView that contains the user's login information |
| 276 LoginView* login_view_; | 132 LoginView* login_view_; |
| 277 | 133 |
| 278 // The PasswordForm sent to the PasswordManager. This is so we can refer to it | |
| 279 // when later notifying the password manager if the credentials were accepted | |
| 280 // or rejected. | |
| 281 // This should only be accessed on the UI loop. | |
| 282 PasswordForm password_form_; | |
| 283 | |
| 284 // Points to the password manager owned by the TabContents requesting auth. | |
| 285 // Can be null if the TabContents is not a TabContents. | |
| 286 // This should only be accessed on the UI loop. | |
| 287 PasswordManager* password_manager_; | |
| 288 | |
| 289 // Cached from the URLRequest, in case it goes NULL on us. | |
| 290 int render_process_host_id_; | |
| 291 int tab_contents_id_; | |
| 292 | |
| 293 DISALLOW_COPY_AND_ASSIGN(LoginHandlerWin); | 134 DISALLOW_COPY_AND_ASSIGN(LoginHandlerWin); |
| 294 }; | 135 }; |
| 295 | 136 |
| 296 // static | 137 // static |
| 297 LoginHandler* LoginHandler::Create(URLRequest* request) { | 138 LoginHandler* LoginHandler::Create(URLRequest* request) { |
| 298 return new LoginHandlerWin(request); | 139 return new LoginHandlerWin(request); |
| 299 } | 140 } |
| OLD | NEW |