1// Copyright 2013 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#ifndef CHROME_BROWSER_SIGNIN_SIGNIN_BROWSERTEST_H_
6#define CHROME_BROWSER_SIGNIN_SIGNIN_BROWSERTEST_H_
7
8#include "base/command_line.h"
9#include "chrome/browser/signin/chrome_signin_client.h"
10#include "chrome/browser/signin/chrome_signin_client_factory.h"
11#include "chrome/browser/signin/signin_promo.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/browser/ui/singleton_tabs.h"
14#include "chrome/browser/ui/tabs/tab_strip_model.h"
15#include "chrome/browser/ui/webui/signin/login_ui_service.h"
16#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/common/url_constants.h"
19#include "chrome/test/base/in_process_browser_test.h"
20#include "chrome/test/base/ui_test_utils.h"
21#include "content/public/browser/notification_service.h"
22#include "content/public/browser/notification_types.h"
23#include "content/public/browser/render_process_host.h"
24#include "content/public/browser/render_view_host.h"
25#include "content/public/browser/web_contents.h"
26#include "content/public/browser/web_contents_observer.h"
27#include "content/public/common/content_switches.h"
28#include "google_apis/gaia/gaia_urls.h"
29#include "net/http/http_status_code.h"
30#include "net/url_request/test_url_fetcher_factory.h"
31#include "net/url_request/url_request_status.h"
32
33namespace {
34const char kNonSigninURL[] = "http://www.google.com";
35}
36
37class SigninBrowserTest : public InProcessBrowserTest {
38 public:
39  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
40    https_server_.reset(new net::SpawnedTestServer(
41        net::SpawnedTestServer::TYPE_HTTPS,
42        net::SpawnedTestServer::kLocalhost,
43        base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))));
44    ASSERT_TRUE(https_server_->Start());
45
46    // Add a host resolver rule to map all outgoing requests to the test server.
47    // This allows us to use "real" hostnames in URLs, which we can use to
48    // create arbitrary SiteInstances.
49    command_line->AppendSwitchASCII(
50        switches::kHostResolverRules,
51        "MAP * " + https_server_->host_port_pair().ToString() +
52            ",EXCLUDE localhost");
53    command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
54    // All tests in this file are for the web based sign in flows.
55    // TODO(guohui): fix tests for inline sign in flows.
56    command_line->AppendSwitch(switches::kEnableWebBasedSignin);
57  }
58
59  virtual void SetUp() OVERRIDE {
60    factory_.reset(new net::URLFetcherImplFactory());
61    fake_factory_.reset(new net::FakeURLFetcherFactory(factory_.get()));
62    fake_factory_->SetFakeResponse(
63        GaiaUrls::GetInstance()->service_login_url(), std::string(),
64        net::HTTP_OK, net::URLRequestStatus::SUCCESS);
65    fake_factory_->SetFakeResponse(
66        GURL(kNonSigninURL), std::string(), net::HTTP_OK,
67        net::URLRequestStatus::SUCCESS);
68    // Yield control back to the InProcessBrowserTest framework.
69    InProcessBrowserTest::SetUp();
70  }
71
72  virtual void TearDown() OVERRIDE {
73    if (fake_factory_.get()) {
74      fake_factory_->ClearFakeResponses();
75      fake_factory_.reset();
76    }
77
78    // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory
79    // we created.
80    net::URLFetcher::CancelAll();
81    factory_.reset();
82    InProcessBrowserTest::TearDown();
83  }
84
85 private:
86  // Fake URLFetcher factory used to mock out GAIA signin.
87  scoped_ptr<net::FakeURLFetcherFactory> fake_factory_;
88
89  // The URLFetcherImplFactory instance used to instantiate |fake_factory_|.
90  scoped_ptr<net::URLFetcherImplFactory> factory_;
91
92  scoped_ptr<net::SpawnedTestServer> https_server_;
93};
94
95// If the one-click-signin feature is not enabled (e.g Chrome OS), we
96// never grant signin privileges to any renderer processes.
97#if defined(ENABLE_ONE_CLICK_SIGNIN)
98const bool kOneClickSigninEnabled = true;
99#else
100const bool kOneClickSigninEnabled = false;
101#endif
102
103// Disabled on Windows due to flakiness. http://crbug.com/249055
104#if defined(OS_WIN)
105#define MAYBE_ProcessIsolation DISABLED_ProcessIsolation
106#else
107#define MAYBE_ProcessIsolation ProcessIsolation
108#endif
109IN_PROC_BROWSER_TEST_F(SigninBrowserTest, MAYBE_ProcessIsolation) {
110  SigninClient* signin =
111      ChromeSigninClientFactory::GetForProfile(browser()->profile());
112  EXPECT_FALSE(signin->HasSigninProcess());
113
114  ui_test_utils::NavigateToURL(browser(), signin::GetPromoURL(
115      signin::SOURCE_NTP_LINK, true));
116  EXPECT_EQ(kOneClickSigninEnabled, signin->HasSigninProcess());
117
118  // Navigating away should change the process.
119  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIOmniboxURL));
120  EXPECT_FALSE(signin->HasSigninProcess());
121
122  ui_test_utils::NavigateToURL(browser(), signin::GetPromoURL(
123      signin::SOURCE_NTP_LINK, true));
124  EXPECT_EQ(kOneClickSigninEnabled, signin->HasSigninProcess());
125
126  content::WebContents* active_tab =
127      browser()->tab_strip_model()->GetActiveWebContents();
128  int active_tab_process_id =
129      active_tab->GetRenderProcessHost()->GetID();
130  EXPECT_EQ(kOneClickSigninEnabled,
131            signin->IsSigninProcess(active_tab_process_id));
132  EXPECT_EQ(0, active_tab->GetRenderViewHost()->GetEnabledBindings());
133
134  // Entry points to signin request "SINGLETON_TAB" mode, so a new request
135  // shouldn't change anything.
136  chrome::NavigateParams params(chrome::GetSingletonTabNavigateParams(
137      browser(),
138      GURL(signin::GetPromoURL(signin::SOURCE_NTP_LINK, false))));
139  params.path_behavior = chrome::NavigateParams::IGNORE_AND_NAVIGATE;
140  ShowSingletonTabOverwritingNTP(browser(), params);
141  EXPECT_EQ(active_tab, browser()->tab_strip_model()->GetActiveWebContents());
142  EXPECT_EQ(kOneClickSigninEnabled,
143            signin->IsSigninProcess(active_tab_process_id));
144
145  // Navigating away should change the process.
146  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
147  EXPECT_FALSE(signin->IsSigninProcess(
148      active_tab->GetRenderProcessHost()->GetID()));
149}
150
151#if defined (OS_MACOSX)
152// crbug.com/375197
153#define MAYBE_NotTrustedAfterRedirect DISABLED_NotTrustedAfterRedirect
154#else
155#define MAYBE_NotTrustedAfterRedirect NotTrustedAfterRedirect
156#endif
157
158IN_PROC_BROWSER_TEST_F(SigninBrowserTest, MAYBE_NotTrustedAfterRedirect) {
159  SigninClient* signin =
160      ChromeSigninClientFactory::GetForProfile(browser()->profile());
161  EXPECT_FALSE(signin->HasSigninProcess());
162
163  GURL url = signin::GetPromoURL(signin::SOURCE_NTP_LINK, true);
164  ui_test_utils::NavigateToURL(browser(), url);
165  EXPECT_EQ(kOneClickSigninEnabled, signin->HasSigninProcess());
166
167  // Navigating in a different tab should not affect the sign-in process.
168  ui_test_utils::NavigateToURLWithDisposition(
169      browser(), GURL(kNonSigninURL), NEW_BACKGROUND_TAB,
170      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
171  EXPECT_EQ(kOneClickSigninEnabled, signin->HasSigninProcess());
172
173  // Navigating away should clear the sign-in process.
174  GURL redirect_url("https://accounts.google.com/server-redirect?"
175      "https://foo.com?service=chromiumsync");
176  ui_test_utils::NavigateToURL(browser(), redirect_url);
177  EXPECT_FALSE(signin->HasSigninProcess());
178}
179
180class BackOnNTPCommitObserver : public content::WebContentsObserver {
181 public:
182  explicit BackOnNTPCommitObserver(content::WebContents* web_contents)
183      : content::WebContentsObserver(web_contents) {
184  }
185
186  virtual void DidCommitProvisionalLoadForFrame(
187      content::RenderFrameHost* render_frame_host,
188      const GURL& url,
189      ui::PageTransition transition_type) OVERRIDE {
190    if (url == GURL(chrome::kChromeUINewTabURL) ||
191        url == GURL(chrome::kChromeSearchLocalNtpUrl)) {
192      content::WindowedNotificationObserver observer(
193          content::NOTIFICATION_NAV_ENTRY_COMMITTED,
194          content::NotificationService::AllSources());
195      web_contents()->GetController().GoBack();
196      observer.Wait();
197    }
198  }
199
200 private:
201  DISALLOW_COPY_AND_ASSIGN(BackOnNTPCommitObserver);
202};
203
204// This is a test for http://crbug.com/257277. It simulates the navigations
205// that occur if the user clicks on the "Skip for now" link at the signin page
206// and initiates a back navigation between the point of Commit and
207// DidStopLoading of the NTP.
208IN_PROC_BROWSER_TEST_F(SigninBrowserTest, SigninSkipForNowAndGoBack) {
209  GURL ntp_url(chrome::kChromeUINewTabURL);
210  GURL start_url = signin::GetPromoURL(signin::SOURCE_START_PAGE, false);
211  GURL skip_url = signin::GetLandingURL("ntp", 1);
212
213  SigninClient* signin =
214      ChromeSigninClientFactory::GetForProfile(browser()->profile());
215  EXPECT_FALSE(signin->HasSigninProcess());
216
217  ui_test_utils::NavigateToURL(browser(), start_url);
218  EXPECT_EQ(kOneClickSigninEnabled, signin->HasSigninProcess());
219
220  content::WebContents* web_contents =
221      browser()->tab_strip_model()->GetActiveWebContents();
222
223  // Simulate clicking on the Skip for now link. It's important to have a
224  // link transition so that OneClickSigninHelper removes the blank page
225  // from the history.
226  chrome::NavigateParams navigate_params(browser(),
227                                         skip_url,
228                                         ui::PAGE_TRANSITION_LINK);
229  ui_test_utils::NavigateToURL(&navigate_params);
230
231  // Register an observer that will navigate back immediately on the commit of
232  // the NTP. This will allow us to hit the race condition of navigating back
233  // before the DidStopLoading message of NTP gets delivered. This must be
234  // created after the navigation to the skip_url has finished loading,
235  // otherwise this observer will navigate back, before the history cleaner
236  // has had a chance to remove the navigation entry.
237  BackOnNTPCommitObserver commit_observer(web_contents);
238
239  // Since OneClickSigninHelper aborts redirect to NTP, thus we expect the
240  // visible URL to be the starting URL.
241  EXPECT_EQ(skip_url, web_contents->GetLastCommittedURL());
242  EXPECT_EQ(start_url, web_contents->GetVisibleURL());
243
244  content::WindowedNotificationObserver observer(
245      content::NOTIFICATION_LOAD_STOP,
246      content::NotificationService::AllSources());
247  observer.Wait();
248  EXPECT_EQ(start_url, web_contents->GetLastCommittedURL());
249}
250#endif  // CHROME_BROWSER_SIGNIN_SIGNIN_BROWSERTEST_H_
251