1 // Copyright (c) 2012 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.
5 #import "chrome/browser/ui/cocoa/login_prompt_cocoa.h"
7 #include "base/mac/bundle_locations.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/strings/string16.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/tab_contents/tab_util.h"
14 #include "chrome/browser/ui/browser_dialogs.h"
15 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
16 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
17 #include "chrome/browser/ui/login/login_prompt.h"
18 #include "components/password_manager/core/browser/login_model.h"
19 #include "components/password_manager/core/browser/password_manager.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/web_contents.h"
22 #include "net/url_request/url_request.h"
23 #include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
25 using autofill::PasswordForm;
26 using content::BrowserThread;
27 using content::WebContents;
29 // ----------------------------------------------------------------------------
32 // This class simply forwards the authentication from the LoginView (on
33 // the UI thread) to the net::URLRequest (on the I/O thread).
34 // This class uses ref counting to ensure that it lives until all InvokeLaters
36 class LoginHandlerMac : public LoginHandler,
37 public ConstrainedWindowMacDelegate {
39 LoginHandlerMac(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
40 : LoginHandler(auth_info, request) {
43 // LoginModelObserver implementation.
44 void OnAutofillDataAvailable(const base::string16& username,
45 const base::string16& password) override {
46 DCHECK_CURRENTLY_ON(BrowserThread::UI);
48 [sheet_controller_ autofillLogin:base::SysUTF16ToNSString(username)
49 password:base::SysUTF16ToNSString(password)];
51 void OnLoginModelDestroying() override {}
54 void BuildViewForPasswordManager(password_manager::PasswordManager* manager,
55 const base::string16& explanation) override {
56 DCHECK_CURRENTLY_ON(BrowserThread::UI);
58 sheet_controller_.reset(
59 [[LoginHandlerSheet alloc] initWithLoginHandler:this]);
63 [sheet_controller_ setExplanation:base::SysUTF16ToNSString(explanation)];
65 // Scary thread safety note: This can potentially be called *after* SetAuth
66 // or CancelAuth (say, if the request was cancelled before the UI thread got
67 // control). However, that's OK since any UI interaction in those functions
68 // will occur via an InvokeLater on the UI thread, which is guaranteed
69 // to happen after this is called (since this was InvokeLater'd first).
70 WebContents* requesting_contents = GetWebContentsForLogin();
71 DCHECK(requesting_contents);
73 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
74 [[CustomConstrainedWindowSheet alloc]
75 initWithCustomWindow:[sheet_controller_ window]]);
76 constrained_window_.reset(new ConstrainedWindowMac(
77 this, requesting_contents, sheet));
82 void CloseDialog() override {
83 // The hosting dialog may have been freed.
84 if (constrained_window_)
85 constrained_window_->CloseWebContentsModalDialog();
88 // Overridden from ConstrainedWindowMacDelegate:
89 void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override {
90 DCHECK_CURRENTLY_ON(BrowserThread::UI);
94 constrained_window_.reset();
95 sheet_controller_.reset();
98 void OnLoginPressed(const base::string16& username,
99 const base::string16& password) {
100 DCHECK_CURRENTLY_ON(BrowserThread::UI);
101 SetAuth(username, password);
104 void OnCancelPressed() {
105 DCHECK_CURRENTLY_ON(BrowserThread::UI);
110 friend class LoginPrompt;
112 ~LoginHandlerMac() override {
113 // This class will be deleted on a non UI thread. Ensure that the UI members
114 // have already been deleted.
115 CHECK(!constrained_window_.get());
116 CHECK(!sheet_controller_.get());
119 // The Cocoa controller of the GUI.
120 base::scoped_nsobject<LoginHandlerSheet> sheet_controller_;
122 scoped_ptr<ConstrainedWindowMac> constrained_window_;
124 DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
128 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
129 net::URLRequest* request) {
130 if (chrome::ToolkitViewsDialogsEnabled())
131 return chrome::CreateLoginHandlerViews(auth_info, request);
132 return new LoginHandlerMac(auth_info, request);
135 // ----------------------------------------------------------------------------
138 @implementation LoginHandlerSheet
140 - (id)initWithLoginHandler:(LoginHandlerMac*)handler {
142 [base::mac::FrameworkBundle() pathForResource:@"HttpAuthLoginSheet"
144 if ((self = [super initWithWindowNibPath:nibPath
147 // Force the nib to load so that all outlets are initialized.
154 // The buttons could be in a modal loop, so disconnect them so they cannot
155 // call back to us after we're dead.
156 [loginButton_ setTarget:nil];
157 [cancelButton_ setTarget:nil];
161 - (IBAction)loginPressed:(id)sender {
162 handler_->OnLoginPressed(
163 base::SysNSStringToUTF16([nameField_ stringValue]),
164 base::SysNSStringToUTF16([passwordField_ stringValue]));
167 - (IBAction)cancelPressed:(id)sender {
168 handler_->OnCancelPressed();
171 - (void)autofillLogin:(NSString*)login password:(NSString*)password {
172 if ([[nameField_ stringValue] length] == 0) {
173 [nameField_ setStringValue:login];
174 [passwordField_ setStringValue:password];
175 [nameField_ selectText:self];
179 - (void)setExplanation:(NSString*)explanation {
181 [explanationField_ setStringValue:explanation];
183 // Resize the text field.
184 CGFloat windowDelta = [GTMUILocalizerAndLayoutTweaker
185 sizeToFitFixedWidthTextField:explanationField_];
187 NSRect newFrame = [[self window] frame];
188 newFrame.size.height += windowDelta;
189 [[self window] setFrame:newFrame display:NO];