cros: Update SAML flow.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / saml / saml_browsertest.cc
blob886e61352ff1bd1715aec7326d51e21d672ef985
1 // Copyright 2014 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.
5 #include "base/command_line.h"
6 #include "base/file_util.h"
7 #include "base/files/file_path.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/path_service.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/chromeos/login/existing_user_controller.h"
16 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
17 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
18 #include "chrome/browser/chromeos/login/user.h"
19 #include "chrome/browser/chromeos/login/user_manager.h"
20 #include "chrome/browser/chromeos/login/webui_login_display.h"
21 #include "chrome/browser/chromeos/login/wizard_controller.h"
22 #include "chrome/browser/lifetime/application_lifetime.h"
23 #include "chrome/common/chrome_paths.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/test/base/in_process_browser_test.h"
26 #include "chromeos/chromeos_switches.h"
27 #include "components/policy/core/browser/browser_policy_connector.h"
28 #include "components/policy/core/common/mock_configuration_policy_provider.h"
29 #include "components/policy/core/common/policy_map.h"
30 #include "components/policy/core/common/policy_types.h"
31 #include "content/public/browser/render_view_host.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/test/browser_test_utils.h"
34 #include "content/public/test/test_utils.h"
35 #include "google_apis/gaia/fake_gaia.h"
36 #include "google_apis/gaia/gaia_switches.h"
37 #include "net/base/url_util.h"
38 #include "net/dns/mock_host_resolver.h"
39 #include "net/test/embedded_test_server/embedded_test_server.h"
40 #include "net/test/embedded_test_server/http_request.h"
41 #include "net/test/embedded_test_server/http_response.h"
42 #include "policy/policy_constants.h"
43 #include "testing/gmock/include/gmock/gmock.h"
44 #include "testing/gtest/include/gtest/gtest.h"
46 using net::test_server::BasicHttpResponse;
47 using net::test_server::HttpRequest;
48 using net::test_server::HttpResponse;
49 using testing::_;
50 using testing::Return;
52 namespace chromeos {
54 namespace {
56 const char kTestAuthSIDCookie[] = "fake-auth-SID-cookie";
57 const char kTestAuthLSIDCookie[] = "fake-auth-LSID-cookie";
58 const char kTestAuthCode[] = "fake-auth-code";
59 const char kTestGaiaUberToken[] = "fake-uber-token";
60 const char kTestAuthLoginAccessToken[] = "fake-access-token";
61 const char kTestRefreshToken[] = "fake-refresh-token";
62 const char kTestSessionSIDCookie[] = "fake-session-SID-cookie";
63 const char kTestSessionLSIDCookie[] = "fake-session-LSID-cookie";
65 const char kFirstSAMLUserEmail[] = "bob@example.com";
66 const char kSecondSAMLUserEmail[] = "alice@example.com";
67 const char kNonSAMLUserEmail[] = "carol@example.com";
69 const char kRelayState[] = "RelayState";
71 // FakeSamlIdp serves IdP auth form and the form submission. The form is
72 // served with the template's RelayState placeholder expanded to the real
73 // RelayState parameter from request. The form submission redirects back to
74 // FakeGaia with the same RelayState.
75 class FakeSamlIdp {
76 public:
77 FakeSamlIdp();
78 ~FakeSamlIdp();
80 void SetUp(const std::string& base_path, const GURL& gaia_url);
82 void SetLoginHTMLTemplate(const std::string& template_file);
83 void SetLoginAuthHTMLTemplate(const std::string& template_file);
85 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request);
87 private:
88 scoped_ptr<HttpResponse> BuildHTMLResponse(const std::string& html_template,
89 const std::string& relay_state,
90 const std::string& next_path);
92 base::FilePath html_template_dir_;
94 std::string login_path_;
95 std::string login_auth_path_;
97 std::string login_html_template_;
98 std::string login_auth_html_template_;
99 GURL gaia_assertion_url_;
101 DISALLOW_COPY_AND_ASSIGN(FakeSamlIdp);
104 FakeSamlIdp::FakeSamlIdp() {
107 FakeSamlIdp::~FakeSamlIdp() {
110 void FakeSamlIdp::SetUp(const std::string& base_path, const GURL& gaia_url) {
111 base::FilePath test_data_dir;
112 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
113 html_template_dir_ = test_data_dir.Append("login");
115 login_path_= base_path;
116 login_auth_path_ = base_path + "Auth";
117 gaia_assertion_url_ = gaia_url.Resolve("/SSO");
120 void FakeSamlIdp::SetLoginHTMLTemplate(const std::string& template_file) {
121 EXPECT_TRUE(base::ReadFileToString(
122 html_template_dir_.Append(template_file),
123 &login_html_template_));
126 void FakeSamlIdp::SetLoginAuthHTMLTemplate(const std::string& template_file) {
127 EXPECT_TRUE(base::ReadFileToString(
128 html_template_dir_.Append(template_file),
129 &login_auth_html_template_));
132 scoped_ptr<HttpResponse> FakeSamlIdp::HandleRequest(
133 const HttpRequest& request) {
134 // The scheme and host of the URL is actually not important but required to
135 // get a valid GURL in order to parse |request.relative_url|.
136 GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
137 std::string request_path = request_url.path();
139 if (request_path == login_path_) {
140 std::string relay_state;
141 net::GetValueForKeyInQuery(request_url, kRelayState, &relay_state);
142 return BuildHTMLResponse(login_html_template_,
143 relay_state,
144 login_auth_path_);
147 if (request_path != login_auth_path_) {
148 // Request not understood.
149 return scoped_ptr<HttpResponse>();
152 std::string relay_state;
153 FakeGaia::GetQueryParameter(request.content, kRelayState, &relay_state);
154 GURL redirect_url = gaia_assertion_url_;
156 if (!login_auth_html_template_.empty()) {
157 return BuildHTMLResponse(login_auth_html_template_,
158 relay_state,
159 redirect_url.spec());
162 redirect_url = net::AppendQueryParameter(
163 redirect_url, "SAMLResponse", "fake_response");
164 redirect_url = net::AppendQueryParameter(
165 redirect_url, kRelayState, relay_state);
167 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
168 http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
169 http_response->AddCustomHeader("Location", redirect_url.spec());
170 return http_response.PassAs<HttpResponse>();
173 scoped_ptr<HttpResponse> FakeSamlIdp::BuildHTMLResponse(
174 const std::string& html_template,
175 const std::string& relay_state,
176 const std::string& next_path) {
177 std::string response_html = html_template;
178 ReplaceSubstringsAfterOffset(&response_html, 0, "$RelayState", relay_state);
179 ReplaceSubstringsAfterOffset(&response_html, 0, "$Post", next_path);
181 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
182 http_response->set_code(net::HTTP_OK);
183 http_response->set_content(response_html);
184 http_response->set_content_type("text/html");
186 return http_response.PassAs<HttpResponse>();
189 } // namespace
191 class SamlTest : public InProcessBrowserTest {
192 public:
193 SamlTest() : saml_load_injected_(false) {}
194 virtual ~SamlTest() {}
196 virtual void SetUp() OVERRIDE {
197 // Start embedded test server here so that we can get server base url
198 // and override Gaia urls in SetupCommandLine.
199 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
201 // Stop IO thread here because no threads are allowed while
202 // spawning sandbox host process. See crbug.com/322732.
203 embedded_test_server()->StopThread();
205 InProcessBrowserTest::SetUp();
208 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
209 host_resolver()->AddRule("*", "127.0.0.1");
212 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
213 command_line->AppendSwitch(switches::kLoginManager);
214 command_line->AppendSwitch(switches::kForceLoginManagerInTests);
215 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
216 command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
218 const GURL& server_url = embedded_test_server()->base_url();
220 std::string gaia_host("gaia");
221 GURL::Replacements replace_gaia_host;
222 replace_gaia_host.SetHostStr(gaia_host);
223 gaia_url_ = server_url.ReplaceComponents(replace_gaia_host);
225 command_line->AppendSwitchASCII(::switches::kGaiaUrl, gaia_url_.spec());
226 command_line->AppendSwitchASCII(::switches::kLsoUrl, gaia_url_.spec());
227 command_line->AppendSwitchASCII(::switches::kGoogleApisUrl,
228 gaia_url_.spec());
229 fake_gaia_.Initialize();
231 std::string saml_idp_host("saml.idp");
232 GURL::Replacements replace_saml_idp_host;
233 replace_saml_idp_host.SetHostStr(saml_idp_host);
234 GURL saml_idp_url = server_url.ReplaceComponents(replace_saml_idp_host);
235 saml_idp_url = saml_idp_url.Resolve("/SAML/SSO");
237 fake_saml_idp_.SetUp(saml_idp_url.path(), gaia_url_);
238 fake_gaia_.RegisterSamlUser(kFirstSAMLUserEmail, saml_idp_url);
239 fake_gaia_.RegisterSamlUser(kSecondSAMLUserEmail, saml_idp_url);
242 virtual void SetUpOnMainThread() OVERRIDE {
243 FakeGaia::MergeSessionParams params;
244 params.auth_sid_cookie = kTestAuthSIDCookie;
245 params.auth_lsid_cookie = kTestAuthLSIDCookie;
246 params.auth_code = kTestAuthCode;
247 params.refresh_token = kTestRefreshToken;
248 params.access_token = kTestAuthLoginAccessToken;
249 params.gaia_uber_token = kTestGaiaUberToken;
250 params.session_sid_cookie = kTestSessionSIDCookie;
251 params.session_lsid_cookie = kTestSessionLSIDCookie;
252 params.email = kFirstSAMLUserEmail;
253 fake_gaia_.SetMergeSessionParams(params);
255 embedded_test_server()->RegisterRequestHandler(
256 base::Bind(&FakeGaia::HandleRequest, base::Unretained(&fake_gaia_)));
257 embedded_test_server()->RegisterRequestHandler(base::Bind(
258 &FakeSamlIdp::HandleRequest, base::Unretained(&fake_saml_idp_)));
260 // Restart the thread as the sandbox host process has already been spawned.
261 embedded_test_server()->RestartThreadAndListen();
263 login_screen_load_observer_.reset(new content::WindowedNotificationObserver(
264 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
265 content::NotificationService::AllSources()));
268 virtual void CleanUpOnMainThread() OVERRIDE {
269 // If the login display is still showing, exit gracefully.
270 if (LoginDisplayHostImpl::default_host()) {
271 base::MessageLoop::current()->PostTask(FROM_HERE,
272 base::Bind(&chrome::AttemptExit));
273 content::RunMessageLoop();
277 WebUILoginDisplay* GetLoginDisplay() {
278 ExistingUserController* controller =
279 ExistingUserController::current_controller();
280 CHECK(controller);
281 return static_cast<WebUILoginDisplay*>(controller->login_display());
284 void WaitForSigninScreen() {
285 WizardController::SkipPostLoginScreensForTesting();
286 WizardController* wizard_controller =
287 chromeos::WizardController::default_controller();
288 CHECK(wizard_controller);
289 wizard_controller->SkipToLoginForTesting(LoginScreenContext());
291 login_screen_load_observer_->Wait();
294 void StartSamlAndWaitForIdpPageLoad(const std::string& gaia_email) {
295 WaitForSigninScreen();
297 if (!saml_load_injected_) {
298 saml_load_injected_ = true;
300 ASSERT_TRUE(content::ExecuteScript(
301 GetLoginUI()->GetWebContents(),
302 "$('gaia-signin').gaiaAuthHost_.addEventListener('authFlowChange',"
303 "function() {"
304 "window.domAutomationController.setAutomationId(0);"
305 "window.domAutomationController.send("
306 "$('gaia-signin').isSAML() ? 'SamlLoaded' : 'GaiaLoaded');"
307 "});"));
310 content::DOMMessageQueue message_queue; // Start observe before SAML.
311 GetLoginDisplay()->ShowSigninScreenForCreds(gaia_email, "");
313 std::string message;
314 ASSERT_TRUE(message_queue.WaitForMessage(&message));
315 EXPECT_EQ("\"SamlLoaded\"", message);
318 void SetSignFormField(const std::string& field_id,
319 const std::string& field_value) {
320 std::string js =
321 "(function(){"
322 "document.getElementById('$FieldId').value = '$FieldValue';"
323 "var e = new Event('input');"
324 "document.getElementById('$FieldId').dispatchEvent(e);"
325 "})();";
326 ReplaceSubstringsAfterOffset(&js, 0, "$FieldId", field_id);
327 ReplaceSubstringsAfterOffset(&js, 0, "$FieldValue", field_value);
328 ExecuteJsInSigninFrame(js);
331 void SendConfirmPassword(const std::string& password_to_confirm) {
332 std::string js =
333 "$('confirm-password-input').value='$Password';"
334 "$('confirm-password').onConfirmPassword_();";
335 ReplaceSubstringsAfterOffset(&js, 0, "$Password", password_to_confirm);
336 ASSERT_TRUE(content::ExecuteScript(GetLoginUI()->GetWebContents(), js));
339 void JsExpect(const std::string& js) {
340 bool result;
341 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
342 GetLoginUI()->GetWebContents(),
343 "window.domAutomationController.send(!!(" + js + "));",
344 &result));
345 EXPECT_TRUE(result) << js;
348 content::WebUI* GetLoginUI() {
349 return static_cast<chromeos::LoginDisplayHostImpl*>(
350 chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI()->web_ui();
353 // Executes Js code in the auth iframe hosted by gaia_auth extension.
354 void ExecuteJsInSigninFrame(const std::string& js) {
355 ASSERT_TRUE(content::ExecuteScriptInFrame(
356 GetLoginUI()->GetWebContents(),
357 "//iframe[@id='signin-frame']\n//iframe",
358 js));
361 FakeSamlIdp* fake_saml_idp() { return &fake_saml_idp_; }
363 protected:
364 scoped_ptr<content::WindowedNotificationObserver> login_screen_load_observer_;
366 private:
367 GURL gaia_url_;
368 FakeGaia fake_gaia_;
369 FakeSamlIdp fake_saml_idp_;
371 bool saml_load_injected_;
373 DISALLOW_COPY_AND_ASSIGN(SamlTest);
376 // Tests that signin frame should have 'saml' class and 'cancel' button is
377 // visible when SAML IdP page is loaded. And 'cancel' button goes back to
378 // gaia on clicking.
379 IN_PROC_BROWSER_TEST_F(SamlTest, SamlUI) {
380 fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
381 StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
383 // Saml flow UI expectations.
384 JsExpect("$('gaia-signin').classList.contains('saml')");
385 JsExpect("!$('cancel-add-user-button').hidden");
387 // Click on 'cancel'.
388 content::DOMMessageQueue message_queue; // Observe before 'cancel'.
389 ASSERT_TRUE(content::ExecuteScript(
390 GetLoginUI()->GetWebContents(),
391 "$('cancel-add-user-button').click();"));
393 // Auth flow should change back to Gaia.
394 std::string message;
395 do {
396 ASSERT_TRUE(message_queue.WaitForMessage(&message));
397 } while (message != "\"GaiaLoaded\"");
399 // Saml flow is gone.
400 JsExpect("!$('gaia-signin').classList.contains('saml')");
403 // Tests the sign-in flow when the credentials passing API is used.
404 IN_PROC_BROWSER_TEST_F(SamlTest, CredentialPassingAPI) {
405 fake_saml_idp()->SetLoginHTMLTemplate("saml_api_login.html");
406 fake_saml_idp()->SetLoginAuthHTMLTemplate("saml_api_login_auth.html");
407 StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
409 // Fill-in the SAML IdP form and submit.
410 SetSignFormField("Email", "fake_user");
411 SetSignFormField("Password", "fake_password");
412 ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
414 // Login should finish login and a session should start.
415 content::WindowedNotificationObserver(
416 chrome::NOTIFICATION_SESSION_STARTED,
417 content::NotificationService::AllSources()).Wait();
420 // Tests the single password scraped flow.
421 IN_PROC_BROWSER_TEST_F(SamlTest, ScrapedSingle) {
422 fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
423 StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
425 // Fill-in the SAML IdP form and submit.
426 SetSignFormField("Email", "fake_user");
427 SetSignFormField("Password", "fake_password");
428 ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
430 // Lands on confirm password screen.
431 OobeScreenWaiter(OobeDisplay::SCREEN_CONFIRM_PASSWORD).Wait();
433 // Enter an unknown password should go back to confirm password screen.
434 SendConfirmPassword("wrong_password");
435 OobeScreenWaiter(OobeDisplay::SCREEN_CONFIRM_PASSWORD).Wait();
437 // Enter a known password should finish login and start session.
438 SendConfirmPassword("fake_password");
439 content::WindowedNotificationObserver(
440 chrome::NOTIFICATION_SESSION_STARTED,
441 content::NotificationService::AllSources()).Wait();
444 // Tests the multiple password scraped flow.
445 IN_PROC_BROWSER_TEST_F(SamlTest, ScrapedMultiple) {
446 fake_saml_idp()->SetLoginHTMLTemplate("saml_login_two_passwords.html");
448 StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
450 SetSignFormField("Email", "fake_user");
451 SetSignFormField("Password", "fake_password");
452 SetSignFormField("Password1", "password1");
453 ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
455 OobeScreenWaiter(OobeDisplay::SCREEN_CONFIRM_PASSWORD).Wait();
457 // Either scraped password should be able to sign-in.
458 SendConfirmPassword("password1");
459 content::WindowedNotificationObserver(
460 chrome::NOTIFICATION_SESSION_STARTED,
461 content::NotificationService::AllSources()).Wait();
464 // Tests the no password scraped flow.
465 IN_PROC_BROWSER_TEST_F(SamlTest, ScrapedNone) {
466 fake_saml_idp()->SetLoginHTMLTemplate("saml_login_no_passwords.html");
468 StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
470 SetSignFormField("Email", "fake_user");
471 ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
473 OobeScreenWaiter(OobeDisplay::SCREEN_FATAL_ERROR).Wait();
476 // Types |bob@example.com| into the GAIA login form but then authenticates as
477 // |alice@example.com| via SAML. Verifies that the logged-in user is correctly
478 // identified as Alice.
479 IN_PROC_BROWSER_TEST_F(SamlTest, UseAutenticatedUserEmailAddress) {
480 fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
481 // Type |bob@example.com| into the GAIA login form.
482 StartSamlAndWaitForIdpPageLoad(kSecondSAMLUserEmail);
484 // Authenticate as alice@example.com via SAML (the |Email| provided here is
485 // irrelevant - the authenticated user's e-mail address that FakeGAIA
486 // reports was set via SetMergeSessionParams()).
487 SetSignFormField("Email", "fake_user");
488 SetSignFormField("Password", "fake_password");
489 ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
491 OobeScreenWaiter(OobeDisplay::SCREEN_CONFIRM_PASSWORD).Wait();
493 SendConfirmPassword("fake_password");
494 content::WindowedNotificationObserver(
495 chrome::NOTIFICATION_SESSION_STARTED,
496 content::NotificationService::AllSources()).Wait();
497 const User* user = UserManager::Get()->GetActiveUser();
498 ASSERT_TRUE(user);
499 EXPECT_EQ(kFirstSAMLUserEmail, user->email());
502 // Tests the password confirm flow: show error on the first failure and
503 // fatal error on the second failure.
504 IN_PROC_BROWSER_TEST_F(SamlTest, PasswordConfirmFlow) {
505 fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
506 StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
508 // Fill-in the SAML IdP form and submit.
509 SetSignFormField("Email", "fake_user");
510 SetSignFormField("Password", "fake_password");
511 ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
513 // Lands on confirm password screen with no error message.
514 OobeScreenWaiter(OobeDisplay::SCREEN_CONFIRM_PASSWORD).Wait();
515 JsExpect("!$('confirm-password').classList.contains('error')");
517 // Enter an unknown password for the first time should go back to confirm
518 // password screen with error message.
519 SendConfirmPassword("wrong_password");
520 OobeScreenWaiter(OobeDisplay::SCREEN_CONFIRM_PASSWORD).Wait();
521 JsExpect("$('confirm-password').classList.contains('error')");
523 // Enter an unknown password 2nd time should go back to confirm password
524 // screen.
525 SendConfirmPassword("wrong_password");
526 OobeScreenWaiter(OobeDisplay::SCREEN_FATAL_ERROR).Wait();
529 class SAMLPolicyTest : public SamlTest {
530 public:
531 SAMLPolicyTest();
532 virtual ~SAMLPolicyTest();
534 // SamlTest:
535 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
536 virtual void SetUpOnMainThread() OVERRIDE;
538 void SetSAMLOfflineSigninTimeLimitPolicy(int limit);
540 protected:
541 policy::MockConfigurationPolicyProvider provider_;
543 private:
544 DISALLOW_COPY_AND_ASSIGN(SAMLPolicyTest);
547 SAMLPolicyTest::SAMLPolicyTest() {
550 SAMLPolicyTest::~SAMLPolicyTest() {
553 void SAMLPolicyTest::SetUpInProcessBrowserTestFixture() {
554 SamlTest::SetUpInProcessBrowserTestFixture();
556 EXPECT_CALL(provider_, IsInitializationComplete(_))
557 .WillRepeatedly(Return(true));
558 policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
561 void SAMLPolicyTest::SetUpOnMainThread() {
562 SamlTest::SetUpOnMainThread();
564 // Pretend that the test users' OAuth tokens are valid.
565 UserManager::Get()->SaveUserOAuthStatus(kFirstSAMLUserEmail,
566 User::OAUTH2_TOKEN_STATUS_VALID);
567 UserManager::Get()->SaveUserOAuthStatus(kNonSAMLUserEmail,
568 User::OAUTH2_TOKEN_STATUS_VALID);
571 void SAMLPolicyTest::SetSAMLOfflineSigninTimeLimitPolicy(int limit) {
572 policy::PolicyMap policy;
573 policy.Set(policy::key::kSAMLOfflineSigninTimeLimit,
574 policy::POLICY_LEVEL_MANDATORY,
575 policy::POLICY_SCOPE_USER,
576 new base::FundamentalValue(limit),
577 NULL);
578 provider_.UpdateChromePolicy(policy);
579 base::RunLoop().RunUntilIdle();
582 IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_NoSAML) {
583 // Set the offline login time limit for SAML users to zero.
584 SetSAMLOfflineSigninTimeLimitPolicy(0);
586 WaitForSigninScreen();
588 // Log in without SAML.
589 GetLoginDisplay()->ShowSigninScreenForCreds(kNonSAMLUserEmail, "password");
591 content::WindowedNotificationObserver(
592 chrome::NOTIFICATION_SESSION_STARTED,
593 content::NotificationService::AllSources()).Wait();
596 // Verifies that the offline login time limit does not affect a user who
597 // authenticated without SAML.
598 IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, NoSAML) {
599 login_screen_load_observer_->Wait();
600 // Verify that offline login is allowed.
601 JsExpect("document.querySelector('#pod-row .signin-button').hidden");
604 IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_SAMLNoLimit) {
605 // Remove the offline login time limit for SAML users.
606 SetSAMLOfflineSigninTimeLimitPolicy(-1);
608 // Log in with SAML.
609 fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
610 StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
612 SetSignFormField("Email", "fake_user");
613 SetSignFormField("Password", "fake_password");
614 ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
616 OobeScreenWaiter(OobeDisplay::SCREEN_CONFIRM_PASSWORD).Wait();
618 SendConfirmPassword("fake_password");
619 content::WindowedNotificationObserver(
620 chrome::NOTIFICATION_SESSION_STARTED,
621 content::NotificationService::AllSources()).Wait();
624 // Verifies that when no offline login time limit is set, a user who
625 // authenticated with SAML is allowed to log in offline.
626 IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, SAMLNoLimit) {
627 login_screen_load_observer_->Wait();
628 // Verify that offline login is allowed.
629 JsExpect("document.querySelector('#pod-row .signin-button').hidden");
632 IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, PRE_SAMLZeroLimit) {
633 // Set the offline login time limit for SAML users to zero.
634 SetSAMLOfflineSigninTimeLimitPolicy(0);
636 // Log in with SAML.
637 fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
638 StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
640 SetSignFormField("Email", "fake_user");
641 SetSignFormField("Password", "fake_password");
642 ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
644 OobeScreenWaiter(OobeDisplay::SCREEN_CONFIRM_PASSWORD).Wait();
646 SendConfirmPassword("fake_password");
647 content::WindowedNotificationObserver(
648 chrome::NOTIFICATION_SESSION_STARTED,
649 content::NotificationService::AllSources()).Wait();
652 // Verifies that when the offline login time limit is exceeded for a user who
653 // authenticated via SAML, that user is forced to log in online the next time.
654 IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, SAMLZeroLimit) {
655 login_screen_load_observer_->Wait();
656 // Verify that offline login is not allowed.
657 JsExpect("!document.querySelector('#pod-row .signin-button').hidden");
660 } // namespace chromeos