Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(346)

Unified Diff: chrome/browser/chromeos/login/saml/saml_browsertest.cc

Issue 781623003: Fix Chrome OS enrollment with SAML accounts (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/login/saml/saml_browsertest.cc
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index f0d0a6db6b3687f8c0fe89320b6d0ca7cb2f5023..e82f1d0b3968d3a17b4f6461df83b3775a106c7b 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <cstring>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
@@ -31,6 +35,7 @@
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/policy/test/local_policy_test_server.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/signin/inline_login_ui.h"
#include "chrome/common/chrome_paths.h"
@@ -45,15 +50,20 @@
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_switches.h"
#include "components/policy/core/common/policy_types.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "google_apis/gaia/fake_gaia.h"
+#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_switches.h"
+#include "google_apis/gaia/gaia_urls.h"
#include "net/base/url_util.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_monster.h"
@@ -103,6 +113,10 @@ const char kSAMLIdPCookieValue2[] = "value-2";
const char kRelayState[] = "RelayState";
+const char kTestUserinfoToken[] = "fake-userinfo-token";
+const char kTestRefreshToken[] = "fake-refresh-token";
+const char kPolicy[] = "{\"managed_users\": [\"*\"]}";
+
// FakeSamlIdp serves IdP auth form and the form submission. The form is
// served with the template's RelayState placeholder expanded to the real
// RelayState parameter from request. The form submission redirects back to
@@ -242,7 +256,7 @@ scoped_ptr<HttpResponse> FakeSamlIdp::BuildHTMLResponse(
class SamlTest : public InProcessBrowserTest {
public:
- SamlTest() : saml_load_injected_(false) {}
+ SamlTest() : gaia_frame_parent_("signin-frame"), saml_load_injected_(false) {}
virtual ~SamlTest() {}
virtual void SetUp() override {
@@ -340,7 +354,7 @@ class SamlTest : public InProcessBrowserTest {
login_screen_load_observer_->Wait();
}
- void StartSamlAndWaitForIdpPageLoad(const std::string& gaia_email) {
+ virtual void StartSamlAndWaitForIdpPageLoad(const std::string& gaia_email) {
WaitForSigninScreen();
if (!saml_load_injected_) {
@@ -415,7 +429,7 @@ class SamlTest : public InProcessBrowserTest {
// Executes JavaScript code in the auth iframe hosted by gaia_auth extension.
void ExecuteJsInSigninFrame(const std::string& js) {
content::RenderFrameHost* frame = InlineLoginUI::GetAuthIframe(
- GetLoginUI()->GetWebContents(), GURL(), "signin-frame");
+ GetLoginUI()->GetWebContents(), GURL(), gaia_frame_parent_);
ASSERT_TRUE(content::ExecuteScript(frame, js));
}
@@ -425,11 +439,14 @@ class SamlTest : public InProcessBrowserTest {
scoped_ptr<content::WindowedNotificationObserver> login_screen_load_observer_;
FakeGaia fake_gaia_;
- private:
- FakeSamlIdp fake_saml_idp_;
+ std::string gaia_frame_parent_;
+
scoped_ptr<HTTPSForwarder> gaia_https_forwarder_;
scoped_ptr<HTTPSForwarder> saml_https_forwarder_;
+ private:
+ FakeSamlIdp fake_saml_idp_;
+
bool saml_load_injected_;
DISALLOW_COPY_AND_ASSIGN(SamlTest);
@@ -639,6 +656,170 @@ IN_PROC_BROWSER_TEST_F(SamlTest, MetaRefreshToHTTPDisallowed) {
WaitForAndGetFatalErrorMessage());
}
+class SAMLEnrollmentTest : public SamlTest,
+ public content::WebContentsObserver {
+ public:
+ SAMLEnrollmentTest();
+ ~SAMLEnrollmentTest() override;
+
+ // SamlTest:
+ void SetUp() override;
+ void SetUpCommandLine(CommandLine* command_line) override;
+ void SetUpOnMainThread() override;
+ void StartSamlAndWaitForIdpPageLoad(const std::string& gaia_email) override;
+
+ // content::WebContentsObserver:
+ void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+ void DidFinishLoad(content::RenderFrameHost* render_frame_host,
+ const GURL& validated_url) override;
+
+ void WaitForEnrollmentSuccess();
+
+ private:
+ scoped_ptr<policy::LocalPolicyTestServer> test_server_;
+ base::ScopedTempDir temp_dir_;
+
+ scoped_ptr<base::RunLoop> run_loop_;
+ content::RenderFrameHost* auth_frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(SAMLEnrollmentTest);
+};
+
+SAMLEnrollmentTest::SAMLEnrollmentTest() : auth_frame_(nullptr) {
+ gaia_frame_parent_ = "oauth-enroll-signin-frame";
+}
+
+SAMLEnrollmentTest::~SAMLEnrollmentTest() {
+}
+
+void SAMLEnrollmentTest::SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ const base::FilePath policy_file =
+ temp_dir_.path().AppendASCII("policy.json");
+ ASSERT_EQ(static_cast<int>(strlen(kPolicy)),
Mattias Nissler (ping if slow) 2014/12/04 19:46:02 If I'm not mistaken, you can just use sizeof inste
bartfab (slow) 2014/12/05 12:34:36 I can use |sizeof(kPolicy) - 1| but that feels mor
Mattias Nissler (ping if slow) 2014/12/05 13:07:09 Well, then the test would fail. Anyhow, fair enoug
+ base::WriteFile(policy_file, kPolicy, strlen(kPolicy)));
+
+ test_server_.reset(new policy::LocalPolicyTestServer(policy_file));
+ ASSERT_TRUE(test_server_->Start());
+
+ SamlTest::SetUp();
+}
+
+void SAMLEnrollmentTest::SetUpCommandLine(CommandLine* command_line) {
+ command_line->AppendSwitchASCII(policy::switches::kDeviceManagementUrl,
+ test_server_->GetServiceURL().spec());
+ command_line->AppendSwitch(policy::switches::kDisablePolicyKeyVerification);
+ command_line->AppendSwitch(switches::kEnterpriseEnrollmentSkipRobotAuth);
Mattias Nissler (ping if slow) 2014/12/04 19:46:02 Any good reason for this?
bartfab (slow) 2014/12/05 12:34:36 The robot account generation code causes an OAuth
Mattias Nissler (ping if slow) 2014/12/05 13:07:09 If I ever get to write an end-to-end FRE/enrollmen
bartfab (slow) 2014/12/15 17:10:21 Done.
+
+ SamlTest::SetUpCommandLine(command_line);
+}
+
+void SAMLEnrollmentTest::SetUpOnMainThread() {
+ Observe(GetLoginUI()->GetWebContents());
+
+ FakeGaia::AccessTokenInfo token_info;
+ token_info.token = kTestUserinfoToken;
+ token_info.scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
+ token_info.scopes.insert(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
+ token_info.audience = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
+ token_info.email = kFirstSAMLUserEmail;
+ fake_gaia_.IssueOAuthToken(kTestRefreshToken, token_info);
+
+ SamlTest::SetUpOnMainThread();
+}
+
+void SAMLEnrollmentTest::StartSamlAndWaitForIdpPageLoad(
+ const std::string& gaia_email) {
+ WaitForSigninScreen();
+ run_loop_.reset(new base::RunLoop);
+ ExistingUserController::current_controller()->OnStartEnterpriseEnrollment();
+ run_loop_->Run();
+
+ SetSignFormField("Email", gaia_email);
+
+ run_loop_.reset(new base::RunLoop);
+ ExecuteJsInSigninFrame("document.getElementById('signIn').click();");
+ run_loop_->Run();
+}
+
+void SAMLEnrollmentTest::RenderFrameCreated(
+ content::RenderFrameHost* render_frame_host) {
+ content::RenderFrameHost* parent = render_frame_host->GetParent();
+ if (!parent || parent->GetFrameName() != gaia_frame_parent_)
+ return;
+
+ // The GAIA extension created the iframe in which the login form will be
+ // shown. Now wait for the login form to finish loading.
+ auth_frame_ = render_frame_host;
+ Observe(content::WebContents::FromRenderFrameHost(auth_frame_));
+}
+
+void SAMLEnrollmentTest::DidFinishLoad(
+ content::RenderFrameHost* render_frame_host,
+ const GURL& validated_url) {
+ if (render_frame_host != auth_frame_)
+ return;
+
+ const GURL origin = validated_url.GetOrigin();
+ if (origin != gaia_https_forwarder_->GetURL("") &&
+ origin != saml_https_forwarder_->GetURL("")) {
+ return;
+ }
+
+ // The GAIA or SAML IdP login form finished loading.
+ if (run_loop_)
+ run_loop_->Quit();
+}
+
+// Waits until the class |oauth-enroll-state-success| becomes set for the
+// enrollment screen, indicating enrollment success.
+void SAMLEnrollmentTest::WaitForEnrollmentSuccess() {
Mattias Nissler (ping if slow) 2014/12/04 19:46:02 Instead of this, why not just observe DeviceCloudP
bartfab (slow) 2014/12/05 12:34:36 This verifies that the enrollment success reaches
Mattias Nissler (ping if slow) 2014/12/05 13:07:09 OK, fair enough. Might additionally want to click
bartfab (slow) 2014/12/15 17:10:21 I had a look. We cannot get at the exit code becau
+ bool done = false;
+ ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+ GetLoginUI()->GetWebContents(),
+ "var enrollmentScreen = document.getElementById('oauth-enrollment');"
+ "function SendReplyIfEnrollmentDone() {"
+ " if (!enrollmentScreen.classList.contains("
+ " 'oauth-enroll-state-success')) {"
+ " return false;"
+ " }"
+ " domAutomationController.send(true);"
+ " observer.disconnect();"
+ " return true;"
+ "}"
+ "var observer = new MutationObserver(SendReplyIfEnrollmentDone);"
+ "if (!SendReplyIfEnrollmentDone()) {"
+ " var options = { attributes: true, attributeFilter: [ 'class' ] };"
+ " observer.observe(enrollmentScreen, options);"
+ "}",
+ &done));
+}
+
+IN_PROC_BROWSER_TEST_F(SAMLEnrollmentTest, WithoutCredentialsPassingAPI) {
+ fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
+ StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
+
+ // Fill-in the SAML IdP form and submit.
+ SetSignFormField("Email", "fake_user");
+ SetSignFormField("Password", "fake_password");
+ ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
+
+ WaitForEnrollmentSuccess();
+}
+
+IN_PROC_BROWSER_TEST_F(SAMLEnrollmentTest, WithCredentialsPassingAPI) {
+ fake_saml_idp()->SetLoginHTMLTemplate("saml_api_login.html");
+ fake_saml_idp()->SetLoginAuthHTMLTemplate("saml_api_login_auth.html");
+ StartSamlAndWaitForIdpPageLoad(kFirstSAMLUserEmail);
+
+ // Fill-in the SAML IdP form and submit.
+ SetSignFormField("Email", "fake_user");
+ SetSignFormField("Password", "fake_password");
+ ExecuteJsInSigninFrame("document.getElementById('Submit').click();");
+
+ WaitForEnrollmentSuccess();
+}
+
class SAMLPolicyTest : public SamlTest {
public:
SAMLPolicyTest();

Powered by Google App Engine
This is Rietveld 408576698