• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5#import "chrome/browser/ui/cocoa/login_prompt_cocoa.h"
6
7#include "base/mac/bundle_locations.h"
8#include "base/mac/mac_util.h"
9#include "base/mac/scoped_nsobject.h"
10#include "base/strings/string16.h"
11#include "base/strings/string_util.h"
12#include "base/strings/sys_string_conversions.h"
13#include "base/strings/utf_string_conversions.h"
14#include "chrome/browser/password_manager/password_manager.h"
15#include "chrome/browser/tab_contents/tab_util.h"
16#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
17#include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
18#include "chrome/browser/ui/login/login_model.h"
19#include "chrome/browser/ui/login/login_prompt.h"
20#include "content/public/browser/browser_thread.h"
21#include "content/public/browser/web_contents.h"
22#include "grit/generated_resources.h"
23#include "net/url_request/url_request.h"
24#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
25#include "ui/base/l10n/l10n_util.h"
26
27using autofill::PasswordForm;
28using content::BrowserThread;
29using content::WebContents;
30
31// ----------------------------------------------------------------------------
32// LoginHandlerMac
33
34// This class simply forwards the authentication from the LoginView (on
35// the UI thread) to the net::URLRequest (on the I/O thread).
36// This class uses ref counting to ensure that it lives until all InvokeLaters
37// have been called.
38class LoginHandlerMac : public LoginHandler,
39                        public ConstrainedWindowMacDelegate {
40 public:
41  LoginHandlerMac(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
42      : LoginHandler(auth_info, request) {
43  }
44
45  // LoginModelObserver implementation.
46  virtual void OnAutofillDataAvailable(
47      const base::string16& username,
48      const base::string16& password) OVERRIDE {
49    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
50
51    [sheet_controller_ autofillLogin:base::SysUTF16ToNSString(username)
52                            password:base::SysUTF16ToNSString(password)];
53  }
54  virtual void OnLoginModelDestroying() OVERRIDE {}
55
56  // LoginHandler:
57  virtual void BuildViewForPasswordManager(
58      PasswordManager* manager,
59      const base::string16& explanation) OVERRIDE {
60    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
61
62    sheet_controller_.reset(
63        [[LoginHandlerSheet alloc] initWithLoginHandler:this]);
64
65    SetModel(manager);
66
67    [sheet_controller_ setExplanation:base::SysUTF16ToNSString(explanation)];
68
69    // Scary thread safety note: This can potentially be called *after* SetAuth
70    // or CancelAuth (say, if the request was cancelled before the UI thread got
71    // control).  However, that's OK since any UI interaction in those functions
72    // will occur via an InvokeLater on the UI thread, which is guaranteed
73    // to happen after this is called (since this was InvokeLater'd first).
74    WebContents* requesting_contents = GetWebContentsForLogin();
75    DCHECK(requesting_contents);
76
77    base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
78        [[CustomConstrainedWindowSheet alloc]
79            initWithCustomWindow:[sheet_controller_ window]]);
80    constrained_window_.reset(new ConstrainedWindowMac(
81        this, requesting_contents, sheet));
82
83    NotifyAuthNeeded();
84  }
85
86  virtual void CloseDialog() OVERRIDE {
87    // The hosting dialog may have been freed.
88    if (constrained_window_)
89      constrained_window_->CloseWebContentsModalDialog();
90  }
91
92  // Overridden from ConstrainedWindowMacDelegate:
93  virtual void OnConstrainedWindowClosed(
94      ConstrainedWindowMac* window) OVERRIDE {
95    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
96    SetModel(NULL);
97    ReleaseSoon();
98
99    constrained_window_.reset();
100    sheet_controller_.reset();
101  }
102
103  void OnLoginPressed(const base::string16& username,
104                      const base::string16& password) {
105    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
106    SetAuth(username, password);
107  }
108
109  void OnCancelPressed() {
110    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
111    CancelAuth();
112  }
113
114 private:
115  friend class LoginPrompt;
116
117  virtual ~LoginHandlerMac() {
118    // This class will be deleted on a non UI thread. Ensure that the UI members
119    // have already been deleted.
120    CHECK(!constrained_window_.get());
121    CHECK(!sheet_controller_.get());
122  }
123
124  // The Cocoa controller of the GUI.
125  base::scoped_nsobject<LoginHandlerSheet> sheet_controller_;
126
127  scoped_ptr<ConstrainedWindowMac> constrained_window_;
128
129  DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
130};
131
132// static
133LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
134                                   net::URLRequest* request) {
135  return new LoginHandlerMac(auth_info, request);
136}
137
138// ----------------------------------------------------------------------------
139// LoginHandlerSheet
140
141@implementation LoginHandlerSheet
142
143- (id)initWithLoginHandler:(LoginHandlerMac*)handler {
144  NSString* nibPath =
145      [base::mac::FrameworkBundle() pathForResource:@"HttpAuthLoginSheet"
146                                             ofType:@"nib"];
147  if ((self = [super initWithWindowNibPath:nibPath
148                                     owner:self])) {
149    handler_ = handler;
150    // Force the nib to load so that all outlets are initialized.
151    [self window];
152  }
153  return self;
154}
155
156- (void)dealloc {
157  // The buttons could be in a modal loop, so disconnect them so they cannot
158  // call back to us after we're dead.
159  [loginButton_ setTarget:nil];
160  [cancelButton_ setTarget:nil];
161  [super dealloc];
162}
163
164- (IBAction)loginPressed:(id)sender {
165  handler_->OnLoginPressed(
166      base::SysNSStringToUTF16([nameField_ stringValue]),
167      base::SysNSStringToUTF16([passwordField_ stringValue]));
168}
169
170- (IBAction)cancelPressed:(id)sender {
171  handler_->OnCancelPressed();
172}
173
174- (void)autofillLogin:(NSString*)login password:(NSString*)password {
175  if ([[nameField_ stringValue] length] == 0) {
176    [nameField_ setStringValue:login];
177    [passwordField_ setStringValue:password];
178    [nameField_ selectText:self];
179  }
180}
181
182- (void)setExplanation:(NSString*)explanation {
183  // Put in the text.
184  [explanationField_ setStringValue:explanation];
185
186  // Resize the text field.
187  CGFloat windowDelta = [GTMUILocalizerAndLayoutTweaker
188       sizeToFitFixedWidthTextField:explanationField_];
189
190  NSRect newFrame = [[self window] frame];
191  newFrame.size.height += windowDelta;
192  [[self window] setFrame:newFrame display:NO];
193}
194
195@end
196