Home | History | Annotate | Download | only in login
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/login/login_prompt.h"
      6 #import "chrome/browser/ui/login/login_prompt_mac.h"
      7 
      8 #include "base/mac/mac_util.h"
      9 #include "base/string_util.h"
     10 #include "base/sys_string_conversions.h"
     11 #include "base/utf_string_conversions.h"
     12 #include "chrome/browser/password_manager/password_manager.h"
     13 #include "chrome/browser/tab_contents/tab_util.h"
     14 #include "chrome/browser/ui/cocoa/constrained_window_mac.h"
     15 #include "chrome/browser/ui/login/login_model.h"
     16 #include "content/browser/browser_thread.h"
     17 #include "content/browser/renderer_host/resource_dispatcher_host.h"
     18 #include "content/browser/tab_contents/navigation_controller.h"
     19 #include "content/browser/tab_contents/tab_contents.h"
     20 #include "grit/generated_resources.h"
     21 #include "net/url_request/url_request.h"
     22 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
     23 #include "ui/base/l10n/l10n_util.h"
     24 
     25 using webkit_glue::PasswordForm;
     26 
     27 // ----------------------------------------------------------------------------
     28 // LoginHandlerMac
     29 
     30 // This class simply forwards the authentication from the LoginView (on
     31 // the UI thread) to the net::URLRequest (on the I/O thread).
     32 // This class uses ref counting to ensure that it lives until all InvokeLaters
     33 // have been called.
     34 class LoginHandlerMac : public LoginHandler,
     35                         public ConstrainedWindowMacDelegateCustomSheet {
     36  public:
     37   LoginHandlerMac(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
     38       : LoginHandler(auth_info, request),
     39         sheet_controller_(nil) {
     40   }
     41 
     42   virtual ~LoginHandlerMac() {
     43   }
     44 
     45   // LoginModelObserver implementation.
     46   virtual void OnAutofillDataAvailable(const std::wstring& username,
     47                                        const std::wstring& password) {
     48     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     49 
     50     [sheet_controller_ autofillLogin:base::SysWideToNSString(username)
     51                             password:base::SysWideToNSString(password)];
     52   }
     53 
     54   // LoginHandler:
     55   virtual void BuildViewForPasswordManager(PasswordManager* manager,
     56                                            const string16& explanation) {
     57     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     58 
     59     // Load nib here instead of in constructor.
     60     sheet_controller_ = [[[LoginHandlerSheet alloc]
     61         initWithLoginHandler:this] autorelease];
     62     init([sheet_controller_ window], sheet_controller_,
     63           @selector(sheetDidEnd:returnCode:contextInfo:));
     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     SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
     75 
     76     NotifyAuthNeeded();
     77   }
     78 
     79   // Overridden from ConstrainedWindowMacDelegate:
     80   virtual void DeleteDelegate() {
     81     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     82 
     83     // The constrained window is going to delete itself; clear our pointer.
     84     SetDialog(NULL);
     85     SetModel(NULL);
     86 
     87     // Close sheet if it's still open, as required by
     88     // ConstrainedWindowMacDelegate.
     89     if (is_sheet_open())
     90       [NSApp endSheet:sheet()];
     91 
     92     ReleaseSoon();
     93   }
     94 
     95   void OnLoginPressed(const string16& username,
     96                       const string16& password) {
     97     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     98 
     99     SetAuth(username, password);
    100   }
    101 
    102   void OnCancelPressed() {
    103     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    104 
    105     CancelAuth();
    106   }
    107 
    108  private:
    109   friend class LoginPrompt;
    110 
    111   // The Cocoa controller of the GUI.
    112   LoginHandlerSheet* sheet_controller_;
    113 
    114   DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
    115 };
    116 
    117 // static
    118 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
    119                                    net::URLRequest* request) {
    120   return new LoginHandlerMac(auth_info, request);
    121 }
    122 
    123 // ----------------------------------------------------------------------------
    124 // LoginHandlerSheet
    125 
    126 @implementation LoginHandlerSheet
    127 
    128 - (id)initWithLoginHandler:(LoginHandlerMac*)handler {
    129   NSString* nibPath =
    130       [base::mac::MainAppBundle() pathForResource:@"HttpAuthLoginSheet"
    131                                           ofType:@"nib"];
    132   if ((self = [super initWithWindowNibPath:nibPath
    133                                      owner:self])) {
    134     handler_ = handler;
    135   }
    136   return self;
    137 }
    138 
    139 - (void)dealloc {
    140   // The buttons could be in a modal loop, so disconnect them so they cannot
    141   // call back to us after we're dead.
    142   [loginButton_ setTarget:nil];
    143   [cancelButton_ setTarget:nil];
    144   [super dealloc];
    145 }
    146 
    147 - (IBAction)loginPressed:(id)sender {
    148   using base::SysNSStringToWide;
    149   [NSApp endSheet:[self window]];
    150   handler_->OnLoginPressed(
    151       base::SysNSStringToUTF16([nameField_ stringValue]),
    152       base::SysNSStringToUTF16([passwordField_ stringValue]));
    153 }
    154 
    155 - (IBAction)cancelPressed:(id)sender {
    156   [NSApp endSheet:[self window]];
    157   handler_->OnCancelPressed();
    158 }
    159 
    160 - (void)sheetDidEnd:(NSWindow*)sheet
    161          returnCode:(int)returnCode
    162         contextInfo:(void *)contextInfo {
    163   [sheet orderOut:self];
    164   // Also called when user navigates to another page while the sheet is open.
    165 }
    166 
    167 - (void)autofillLogin:(NSString*)login password:(NSString*)password {
    168   if ([[nameField_ stringValue] length] == 0) {
    169     [nameField_ setStringValue:login];
    170     [passwordField_ setStringValue:password];
    171     [nameField_ selectText:self];
    172   }
    173 }
    174 
    175 - (void)setExplanation:(NSString*)explanation {
    176   // Put in the text.
    177   [explanationField_ setStringValue:explanation];
    178 
    179   // Resize the TextField.
    180   CGFloat explanationShift =
    181       [GTMUILocalizerAndLayoutTweaker
    182        sizeToFitFixedWidthTextField:explanationField_];
    183 
    184   // Resize the window (no shifting needed due to window layout).
    185   NSSize windowDelta = NSMakeSize(0, explanationShift);
    186   [GTMUILocalizerAndLayoutTweaker
    187       resizeWindowWithoutAutoResizingSubViews:[self window]
    188                                         delta:windowDelta];
    189 }
    190 
    191 @end
    192