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