| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/auto_login_prompter.h" |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/logging.h" |
| #include "base/prefs/pref_service.h" |
| #include "chrome/browser/google/google_url_tracker.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/profile_oauth2_token_service.h" |
| #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" |
| #include "chrome/browser/signin/signin_manager.h" |
| #include "chrome/browser/signin/signin_manager_factory.h" |
| #include "chrome/browser/tab_contents/tab_util.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/auto_login_parser/auto_login_parser.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/web_contents.h" |
| #include "net/url_request/url_request.h" |
| #include "url/gurl.h" |
| |
| using content::BrowserThread; |
| using content::WebContents; |
| |
| namespace { |
| |
| #if !defined(OS_ANDROID) |
| bool FetchUsernameThroughSigninManager(Profile* profile, std::string* output) { |
| // In an incognito window these services are not available. |
| SigninManagerBase* signin_manager = |
| SigninManagerFactory::GetInstance()->GetForProfile(profile); |
| if (!signin_manager) |
| return false; |
| |
| ProfileOAuth2TokenService* token_service = |
| ProfileOAuth2TokenServiceFactory::GetForProfile(profile); |
| if (!token_service || !token_service->RefreshTokenIsAvailable( |
| token_service->GetPrimaryAccountId())) { |
| return false; |
| } |
| |
| *output = signin_manager->GetAuthenticatedUsername(); |
| return true; |
| } |
| #endif // !defined(OS_ANDROID) |
| |
| } // namespace |
| |
| AutoLoginPrompter::AutoLoginPrompter(WebContents* web_contents, |
| const Params& params, |
| const GURL& url) |
| : WebContentsObserver(web_contents), |
| params_(params), |
| url_(url), |
| infobar_shown_(false) { |
| if (!web_contents->IsLoading()) { |
| // If the WebContents isn't loading a page, the load notification will never |
| // be triggered. Try adding the InfoBar now. |
| AddInfoBarToWebContents(); |
| } |
| } |
| |
| AutoLoginPrompter::~AutoLoginPrompter() { |
| } |
| |
| // static |
| void AutoLoginPrompter::ShowInfoBarIfPossible(net::URLRequest* request, |
| int child_id, |
| int route_id) { |
| if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAutologin)) |
| return; |
| |
| // See if the response contains the X-Auto-Login header. If so, this was |
| // a request for a login page, and the server is allowing the browser to |
| // suggest auto-login, if available. |
| Params params; |
| // Currently we only accept GAIA credentials in Chrome. |
| if (!auto_login_parser::ParserHeaderInResponse( |
| request, auto_login_parser::ONLY_GOOGLE_COM, ¶ms.header)) |
| return; |
| |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&ShowInfoBarUIThread, |
| params, request->url(), child_id, route_id)); |
| } |
| |
| |
| // static |
| void AutoLoginPrompter::ShowInfoBarUIThread(Params params, |
| const GURL& url, |
| int child_id, |
| int route_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| WebContents* web_contents = tab_util::GetWebContentsByID(child_id, route_id); |
| if (!web_contents) |
| return; |
| |
| Profile* profile = |
| Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| |
| if (!profile->GetPrefs()->GetBoolean(prefs::kAutologinEnabled)) |
| return; |
| |
| #if !defined(OS_ANDROID) |
| // On Android, the username is fetched on the Java side from the |
| // AccountManager provided by the platform. |
| if (!FetchUsernameThroughSigninManager(profile, ¶ms.username)) |
| return; |
| #endif |
| |
| // Make sure that |account|, if specified, matches the logged in user. |
| // However, |account| is usually empty. |
| if (!params.username.empty() && !params.header.account.empty() && |
| params.username != params.header.account) |
| return; |
| // We can't add the infobar just yet, since we need to wait for the tab to |
| // finish loading. If we don't, the info bar appears and then disappears |
| // immediately. Create an AutoLoginPrompter instance to listen for the |
| // relevant notifications; it will delete itself. |
| new AutoLoginPrompter(web_contents, params, url); |
| } |
| |
| void AutoLoginPrompter::DidStopLoading( |
| content::RenderViewHost* render_view_host) { |
| AddInfoBarToWebContents(); |
| delete this; |
| } |
| |
| void AutoLoginPrompter::WebContentsDestroyed(WebContents* web_contents) { |
| // The WebContents was destroyed before the navigation completed. |
| delete this; |
| } |
| |
| void AutoLoginPrompter::AddInfoBarToWebContents() { |
| if (!infobar_shown_) |
| infobar_shown_ = AutoLoginInfoBarDelegate::Create(web_contents(), params_); |
| } |