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
;
50 using testing::Return
;
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.
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
);
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_
,
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_
,
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
>();
191 class SamlTest
: public InProcessBrowserTest
{
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
,
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();
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',"
304 "window.domAutomationController.setAutomationId(0);"
305 "window.domAutomationController.send("
306 "$('gaia-signin').isSAML() ? 'SamlLoaded' : 'GaiaLoaded');"
310 content::DOMMessageQueue message_queue
; // Start observe before SAML.
311 GetLoginDisplay()->ShowSigninScreenForCreds(gaia_email
, "");
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
) {
322 "document.getElementById('$FieldId').value = '$FieldValue';"
323 "var e = new Event('input');"
324 "document.getElementById('$FieldId').dispatchEvent(e);"
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
) {
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
) {
341 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
342 GetLoginUI()->GetWebContents(),
343 "window.domAutomationController.send(!!(" + js
+ "));",
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",
361 FakeSamlIdp
* fake_saml_idp() { return &fake_saml_idp_
; }
364 scoped_ptr
<content::WindowedNotificationObserver
> login_screen_load_observer_
;
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
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.
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();
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
525 SendConfirmPassword("wrong_password");
526 OobeScreenWaiter(OobeDisplay::SCREEN_FATAL_ERROR
).Wait();
529 class SAMLPolicyTest
: public SamlTest
{
532 virtual ~SAMLPolicyTest();
535 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE
;
536 virtual void SetUpOnMainThread() OVERRIDE
;
538 void SetSAMLOfflineSigninTimeLimitPolicy(int limit
);
541 policy::MockConfigurationPolicyProvider provider_
;
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
),
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);
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);
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