Home | History | Annotate | Download | only in ui
      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 #include "chrome/browser/ui/auto_login_prompter.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/logging.h"
     10 #include "base/prefs/pref_service.h"
     11 #include "chrome/browser/google/google_url_tracker.h"
     12 #include "chrome/browser/infobars/infobar_service.h"
     13 #include "chrome/browser/profiles/profile.h"
     14 #include "chrome/browser/signin/profile_oauth2_token_service.h"
     15 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     16 #include "chrome/browser/signin/signin_manager.h"
     17 #include "chrome/browser/signin/signin_manager_factory.h"
     18 #include "chrome/browser/tab_contents/tab_util.h"
     19 #include "chrome/common/chrome_switches.h"
     20 #include "chrome/common/pref_names.h"
     21 #include "components/auto_login_parser/auto_login_parser.h"
     22 #include "content/public/browser/browser_thread.h"
     23 #include "content/public/browser/web_contents.h"
     24 #include "net/url_request/url_request.h"
     25 #include "url/gurl.h"
     26 
     27 using content::BrowserThread;
     28 using content::WebContents;
     29 
     30 namespace {
     31 
     32 bool FetchUsernameThroughSigninManager(Profile* profile, std::string* output) {
     33   // In an incognito window these services are not available.
     34   ProfileOAuth2TokenService* token_service =
     35       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
     36   if (!token_service || !token_service->RefreshTokenIsAvailable())
     37     return false;
     38 
     39   SigninManagerBase* signin_manager =
     40       SigninManagerFactory::GetInstance()->GetForProfile(profile);
     41   if (!signin_manager)
     42     return false;
     43 
     44   *output = signin_manager->GetAuthenticatedUsername();
     45   return true;
     46 }
     47 
     48 }  // namespace
     49 
     50 AutoLoginPrompter::AutoLoginPrompter(WebContents* web_contents,
     51                                      const Params& params,
     52                                      const GURL& url)
     53     : WebContentsObserver(web_contents),
     54       params_(params),
     55       url_(url),
     56       infobar_shown_(false) {
     57   if (!web_contents->IsLoading()) {
     58     // If the WebContents isn't loading a page, the load notification will never
     59     // be triggered.  Try adding the InfoBar now.
     60     AddInfoBarToWebContents();
     61   }
     62 }
     63 
     64 AutoLoginPrompter::~AutoLoginPrompter() {
     65 }
     66 
     67 // static
     68 void AutoLoginPrompter::ShowInfoBarIfPossible(net::URLRequest* request,
     69                                               int child_id,
     70                                               int route_id) {
     71   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAutologin))
     72       return;
     73 
     74   // See if the response contains the X-Auto-Login header.  If so, this was
     75   // a request for a login page, and the server is allowing the browser to
     76   // suggest auto-login, if available.
     77   Params params;
     78   // Currently we only accept GAIA credentials in Chrome.
     79   if (!auto_login_parser::ParserHeaderInResponse(
     80           request, auto_login_parser::ONLY_GOOGLE_COM, &params.header))
     81     return;
     82 
     83   BrowserThread::PostTask(
     84       BrowserThread::UI, FROM_HERE,
     85       base::Bind(&ShowInfoBarUIThread,
     86                  params, request->url(), child_id, route_id));
     87 }
     88 
     89 
     90 // static
     91 void AutoLoginPrompter::ShowInfoBarUIThread(Params params,
     92                                             const GURL& url,
     93                                             int child_id,
     94                                             int route_id) {
     95   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     96   WebContents* web_contents = tab_util::GetWebContentsByID(child_id, route_id);
     97   if (!web_contents)
     98     return;
     99 
    100   Profile* profile =
    101       Profile::FromBrowserContext(web_contents->GetBrowserContext());
    102 
    103   if (!profile->GetPrefs()->GetBoolean(prefs::kAutologinEnabled))
    104     return;
    105 
    106 #if !defined(OS_ANDROID)
    107   // On Android, the username is fetched on the Java side from the
    108   // AccountManager provided by the platform.
    109   if (!FetchUsernameThroughSigninManager(profile, &params.username))
    110     return;
    111 #endif
    112 
    113   // Make sure that |account|, if specified, matches the logged in user.
    114   // However, |account| is usually empty.
    115   if (!params.username.empty() && !params.header.account.empty() &&
    116       params.username != params.header.account)
    117     return;
    118   // We can't add the infobar just yet, since we need to wait for the tab to
    119   // finish loading.  If we don't, the info bar appears and then disappears
    120   // immediately.  Create an AutoLoginPrompter instance to listen for the
    121   // relevant notifications; it will delete itself.
    122   new AutoLoginPrompter(web_contents, params, url);
    123 }
    124 
    125 void AutoLoginPrompter::DidStopLoading(
    126     content::RenderViewHost* render_view_host) {
    127   AddInfoBarToWebContents();
    128   delete this;
    129 }
    130 
    131 void AutoLoginPrompter::WebContentsDestroyed(WebContents* web_contents) {
    132   // The WebContents was destroyed before the navigation completed.
    133   delete this;
    134 }
    135 
    136 void AutoLoginPrompter::AddInfoBarToWebContents() {
    137   if (infobar_shown_)
    138     return;
    139 
    140   InfoBarService* infobar_service =
    141       InfoBarService::FromWebContents(web_contents());
    142   // |infobar_service| is NULL for WebContents hosted in WebDialog.
    143   if (infobar_service) {
    144     AutoLoginInfoBarDelegate::Create(infobar_service, params_);
    145     infobar_shown_ = true;
    146   }
    147 }
    148