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.
9 #include "base/command_line.h"
10 #include "base/run_loop.h"
11 #include "base/stl_util.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/chromeos/login/existing_user_controller.h"
15 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
16 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
17 #include "chrome/browser/chromeos/login/wizard_controller.h"
18 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
19 #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
20 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/test/base/in_process_browser_test.h"
23 #include "chromeos/chromeos_switches.h"
24 #include "components/policy/core/common/cloud/device_management_service.h"
25 #include "components/policy/core/common/policy_switches.h"
26 #include "components/user_manager/user_manager.h"
27 #include "content/public/browser/notification_observer.h"
28 #include "content/public/browser/notification_registrar.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/test/test_utils.h"
31 #include "google_apis/gaia/gaia_switches.h"
32 #include "google_apis/gaia/gaia_urls.h"
33 #include "net/http/http_status_code.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h"
35 #include "net/test/embedded_test_server/http_request.h"
36 #include "net/test/embedded_test_server/http_response.h"
37 #include "policy/proto/device_management_backend.pb.h"
38 #include "testing/gtest/include/gtest/gtest.h"
44 namespace em
= enterprise_management
;
46 const char kDomain
[] = "domain.com";
47 const char kUsername
[] = "user@domain.com";
48 const char kUsernameOtherDomain
[] = "user@other.com";
50 const char kOAuthCodeCookie
[] = "oauth_code=1234; Secure; HttpOnly";
52 const char kOAuth2TokenPairData
[] =
54 " \"refresh_token\": \"1234\","
55 " \"access_token\": \"5678\","
56 " \"expires_in\": 3600"
59 const char kOAuth2AccessTokenData
[] =
61 " \"access_token\": \"5678\","
62 " \"expires_in\": 3600"
65 const char kDMRegisterRequest
[] = "/device_management?request=register";
66 const char kDMPolicyRequest
[] = "/device_management?request=policy";
68 void CopyLockResult(base::RunLoop
* loop
,
69 policy::EnterpriseInstallAttributes::LockResult
* out
,
70 policy::EnterpriseInstallAttributes::LockResult result
) {
77 struct BlockingLoginTestParam
{
80 const bool enroll_device
;
81 const bool use_webview
;
84 class BlockingLoginTest
85 : public OobeBaseTest
,
86 public content::NotificationObserver
,
87 public testing::WithParamInterface
<BlockingLoginTestParam
> {
89 BlockingLoginTest() : profile_added_(NULL
) {
90 set_use_webview(GetParam().use_webview
);
93 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
94 OobeBaseTest::SetUpCommandLine(command_line
);
96 command_line
->AppendSwitchASCII(
97 policy::switches::kDeviceManagementUrl
,
98 embedded_test_server()->GetURL("/device_management").spec());
101 void SetUpOnMainThread() override
{
103 chrome::NOTIFICATION_PROFILE_ADDED
,
104 content::NotificationService::AllSources());
106 OobeBaseTest::SetUpOnMainThread();
109 void TearDownOnMainThread() override
{
111 EXPECT_TRUE(responses_
.empty());
112 STLDeleteElements(&responses_
);
113 OobeBaseTest::TearDownOnMainThread();
116 void Observe(int type
,
117 const content::NotificationSource
& source
,
118 const content::NotificationDetails
& details
) override
{
119 ASSERT_EQ(chrome::NOTIFICATION_PROFILE_ADDED
, type
);
120 ASSERT_FALSE(profile_added_
);
121 profile_added_
= content::Source
<Profile
>(source
).ptr();
124 void RunUntilIdle() {
125 base::RunLoop().RunUntilIdle();
128 policy::BrowserPolicyConnectorChromeOS
* browser_policy_connector() {
129 return g_browser_process
->platform_part()
130 ->browser_policy_connector_chromeos();
133 void EnrollDevice(const std::string
& username
) {
135 policy::EnterpriseInstallAttributes::LockResult result
;
136 browser_policy_connector()->GetInstallAttributes()->LockDevice(
137 username
, policy::DEVICE_MODE_ENTERPRISE
, "100200300",
138 base::Bind(&CopyLockResult
, &loop
, &result
));
140 EXPECT_EQ(policy::EnterpriseInstallAttributes::LOCK_SUCCESS
, result
);
144 void Login(const std::string
& username
) {
145 content::WindowedNotificationObserver
session_started_observer(
146 chrome::NOTIFICATION_SESSION_STARTED
,
147 content::NotificationService::AllSources());
149 ExistingUserController
* controller
=
150 ExistingUserController::current_controller();
151 ASSERT_TRUE(controller
);
152 WebUILoginDisplay
* login_display
=
153 static_cast<WebUILoginDisplay
*>(controller
->login_display());
154 ASSERT_TRUE(login_display
);
156 login_display
->ShowSigninScreenForCreds(username
, "password");
158 // Wait for the session to start after submitting the credentials. This
159 // will wait until all the background requests are done.
160 session_started_observer
.Wait();
163 // Handles an HTTP request sent to the test server. This handler either
164 // uses a canned response in |responses_| if the request path matches one
165 // of the URLs that we mock, otherwise this handler delegates to |fake_gaia_|.
166 scoped_ptr
<net::test_server::HttpResponse
> HandleRequest(
167 const net::test_server::HttpRequest
& request
) {
168 scoped_ptr
<net::test_server::HttpResponse
> response
;
170 GaiaUrls
* gaia
= GaiaUrls::GetInstance();
171 if (request
.relative_url
== gaia
->client_login_to_oauth2_url().path() ||
172 request
.relative_url
== gaia
->oauth2_token_url().path() ||
173 request
.relative_url
.find(kDMRegisterRequest
) == 0 ||
174 request
.relative_url
.find(kDMPolicyRequest
) == 0) {
175 if (!responses_
.empty()) {
176 response
.reset(responses_
.back());
177 responses_
.pop_back();
181 return response
.Pass();
184 // Creates a new canned response that will respond with the given HTTP
185 // status |code|. That response is appended to |responses_| and will be the
186 // next response used.
187 // Returns a reference to that response, so that it can be further customized.
188 net::test_server::BasicHttpResponse
& PushResponse(net::HttpStatusCode code
) {
189 net::test_server::BasicHttpResponse
* response
=
190 new net::test_server::BasicHttpResponse();
191 response
->set_code(code
);
192 responses_
.push_back(response
);
196 // Returns the body of the register response from the policy server.
197 std::string
GetRegisterResponse() {
198 em::DeviceManagementResponse response
;
199 em::DeviceRegisterResponse
* register_response
=
200 response
.mutable_register_response();
201 register_response
->set_device_management_token("1234");
202 register_response
->set_enrollment_type(
203 em::DeviceRegisterResponse::ENTERPRISE
);
205 EXPECT_TRUE(response
.SerializeToString(&data
));
209 // Returns the body of the fetch response from the policy server.
210 std::string
GetPolicyResponse() {
211 em::DeviceManagementResponse response
;
212 response
.mutable_policy_response()->add_response();
214 EXPECT_TRUE(response
.SerializeToString(&data
));
219 void RegisterAdditionalRequestHandlers() override
{
220 embedded_test_server()->RegisterRequestHandler(
221 base::Bind(&BlockingLoginTest::HandleRequest
, base::Unretained(this)));
224 Profile
* profile_added_
;
227 std::vector
<net::test_server::HttpResponse
*> responses_
;
228 content::NotificationRegistrar registrar_
;
230 DISALLOW_COPY_AND_ASSIGN(BlockingLoginTest
);
233 // http://crbug.com/452523
234 #if defined(MEMORY_SANITIZER)
235 #define MAYBE_LoginBlocksForUser DISABLED_LoginBlocksForUser
237 #define MAYBE_LoginBlocksForUser LoginBlocksForUser
239 IN_PROC_BROWSER_TEST_P(BlockingLoginTest
, MAYBE_LoginBlocksForUser
) {
240 // Verify that there isn't a logged in user when the test starts.
241 user_manager::UserManager
* user_manager
= user_manager::UserManager::Get();
242 EXPECT_FALSE(user_manager
->IsUserLoggedIn());
243 EXPECT_FALSE(browser_policy_connector()->IsEnterpriseManaged());
244 EXPECT_FALSE(profile_added_
);
246 // Enroll the device, if enrollment is enabled for this test instance.
247 if (GetParam().enroll_device
) {
248 EnrollDevice(kUsername
);
250 EXPECT_FALSE(user_manager
->IsUserLoggedIn());
251 EXPECT_TRUE(browser_policy_connector()->IsEnterpriseManaged());
252 EXPECT_EQ(kDomain
, browser_policy_connector()->GetEnterpriseDomain());
253 EXPECT_FALSE(profile_added_
);
254 EXPECT_EQ(policy::USER_AFFILIATION_MANAGED
,
255 browser_policy_connector()->GetUserAffiliation(kUsername
));
257 EXPECT_FALSE(user_manager
->IsKnownUser(kUsername
));
260 // Skip the OOBE, go to the sign-in screen, and wait for the login screen to
262 WaitForSigninScreen();
263 EXPECT_FALSE(profile_added_
);
265 // Prepare the fake HTTP responses.
266 if (GetParam().steps
< 5) {
267 // If this instance is not going to complete the entire flow successfully
268 // then the last step will fail.
270 // This response body is important to make the gaia fetcher skip its delayed
271 // retry behavior, which makes testing harder. If this is sent to the policy
272 // fetchers then it will make them fail too.
273 PushResponse(net::HTTP_UNAUTHORIZED
).set_content("Error=AccountDeleted");
276 // Push a response for each step that is going to succeed, in reverse order.
277 switch (GetParam().steps
) {
279 ADD_FAILURE() << "Invalid step number: " << GetParam().steps
;
283 PushResponse(net::HTTP_OK
).set_content(GetPolicyResponse());
286 PushResponse(net::HTTP_OK
).set_content(GetRegisterResponse());
289 PushResponse(net::HTTP_OK
).set_content(kOAuth2AccessTokenData
);
292 PushResponse(net::HTTP_OK
).set_content(kOAuth2TokenPairData
);
295 PushResponse(net::HTTP_OK
)
296 .AddCustomHeader("Set-Cookie", kOAuthCodeCookie
);
303 // Login now. This verifies that logging in with the canned responses (which
304 // may include failures) won't be blocked due to the potential failures.
305 EXPECT_FALSE(profile_added_
);
306 Login(GetParam().username
);
307 EXPECT_TRUE(profile_added_
);
308 ASSERT_TRUE(user_manager
->IsUserLoggedIn());
309 EXPECT_TRUE(user_manager
->IsCurrentUserNew());
312 const BlockingLoginTestParam kBlockinLoginTestCases
[] = {
313 {0, kUsername
, true, false},
314 {1, kUsername
, true, false},
315 {2, kUsername
, true, false},
316 {3, kUsername
, true, false},
317 {4, kUsername
, true, false},
318 {5, kUsername
, true, false},
319 {0, kUsername
, false, false},
320 {1, kUsername
, false, false},
321 {2, kUsername
, false, false},
322 {3, kUsername
, false, false},
323 {4, kUsername
, false, false},
324 {5, kUsername
, false, false},
325 {0, kUsernameOtherDomain
, true, false},
326 {1, kUsernameOtherDomain
, true, false},
327 {2, kUsernameOtherDomain
, true, false},
328 {3, kUsernameOtherDomain
, true, false},
329 {4, kUsernameOtherDomain
, true, false},
330 {5, kUsernameOtherDomain
, true, false},
332 {0, kUsername
, true, true},
333 {1, kUsername
, true, true},
334 {2, kUsername
, true, true},
335 {3, kUsername
, true, true},
336 {4, kUsername
, true, true},
337 {5, kUsername
, true, true},
338 {0, kUsername
, false, true},
339 {1, kUsername
, false, true},
340 {2, kUsername
, false, true},
341 {3, kUsername
, false, true},
342 {4, kUsername
, false, true},
343 {5, kUsername
, false, true},
344 {0, kUsernameOtherDomain
, true, true},
345 {1, kUsernameOtherDomain
, true, true},
346 {2, kUsernameOtherDomain
, true, true},
347 {3, kUsernameOtherDomain
, true, true},
348 {4, kUsernameOtherDomain
, true, true},
349 {5, kUsernameOtherDomain
, true, true},
352 INSTANTIATE_TEST_CASE_P(BlockingLoginTestInstance
,
354 testing::ValuesIn(kBlockinLoginTestCases
));
356 } // namespace chromeos