summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorkhmel <khmel@chromium.org>2016-01-28 16:37:29 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-29 00:38:56 +0000
commit0d5f977b77bc8d3c9f9dd78724fe7eecd6066e73 (patch)
tree30120652b5cf0bf46ba8b4b2e66834c6621179af /chrome
parent1dc58a0a864e5ad4914b8dc0d4392d6ba2bb5ffe (diff)
downloadchromium_src-0d5f977b77bc8d3c9f9dd78724fe7eecd6066e73.zip
chromium_src-0d5f977b77bc8d3c9f9dd78724fe7eecd6066e73.tar.gz
chromium_src-0d5f977b77bc8d3c9f9dd78724fe7eecd6066e73.tar.bz2
arc: Fetch and pass auth code from Chrome to ARC instance.
This supports communication via Google api to get an auth code for GMS Core client and pass it to ARC instance. There are two types of getting the auth code. Firstly, we try to get it silently and secondary, in case when an additional input is required from the user WebView dialog is shown. Changed logic of starting ARC instance. Now its start is controlled by ArcAuthService after communication with Google auth servers. BUG=571146 TEST=Provide additional unit_tests. TEST=logcat shows that auth code is passed to ARC instance. Both modes are tested: silent and WebView based (can be forced by re-imaging) Review URL: https://codereview.chromium.org/1618193003 Cr-Commit-Position: refs/heads/master@{#372222}
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/chromeos/arc/arc_auth_service.cc159
-rw-r--r--chrome/browser/chromeos/arc/arc_auth_service.h78
-rw-r--r--chrome/browser/chromeos/arc/arc_auth_service_unittest.cc164
-rw-r--r--chrome/browser/chromeos/arc/arc_auth_ui.cc108
-rw-r--r--chrome/browser/chromeos/arc/arc_auth_ui.h76
-rw-r--r--chrome/browser/chromeos/login/session/user_session_manager.cc7
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate.h22
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc40
-rw-r--r--chrome/chrome_browser_chromeos.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi5
10 files changed, 591 insertions, 70 deletions
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.cc b/chrome/browser/chromeos/arc/arc_auth_service.cc
index 46a2cea..4638797 100644
--- a/chrome/browser/chromeos/arc/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/arc_auth_service.cc
@@ -6,15 +6,53 @@
#include <utility>
+#include "chrome/browser/chromeos/arc/arc_auth_ui.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/arc/arc_bridge_service.h"
+
namespace arc {
+namespace {
+
+// Weak pointer. This class is owned by ArcServiceManager.
+ArcAuthService* arc_auth_service = nullptr;
+
+// Skip creating UI in unit tests
+bool disable_ui_for_testing = false;
+
+const char kStateDisable[] = "DISABLE";
+const char kStateFetchingCode[] = "FETCHING_CODE";
+const char kStateNoCode[] = "NO_CODE";
+const char kStateEnable[] = "ENABLE";
+
+} // namespace
+
ArcAuthService::ArcAuthService(ArcBridgeService* bridge_service)
: ArcService(bridge_service), binding_(this) {
+ DCHECK(!arc_auth_service);
+ arc_auth_service = this;
+
arc_bridge_service()->AddObserver(this);
}
ArcAuthService::~ArcAuthService() {
arc_bridge_service()->RemoveObserver(this);
+ CloseUI();
+
+ DCHECK(arc_auth_service == this);
+ arc_auth_service = nullptr;
+}
+
+// static
+ArcAuthService* ArcAuthService::Get() {
+ DCHECK(arc_auth_service);
+ DCHECK(arc_auth_service->thread_checker_.CalledOnValidThread());
+ return arc_auth_service;
+}
+
+// static
+void ArcAuthService::DisableUIForTesting() {
+ disable_ui_for_testing = true;
}
void ArcAuthService::OnAuthInstanceReady() {
@@ -22,9 +60,126 @@ void ArcAuthService::OnAuthInstanceReady() {
binding_.CreateInterfacePtrAndBind());
}
+std::string ArcAuthService::GetAndResetAutoCode() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ std::string auth_code;
+ auth_code_.swap(auth_code);
+ return auth_code;
+}
+
void ArcAuthService::GetAuthCode(const GetAuthCodeCallback& callback) {
- // TODO(victorhsieh): request auth code from LSO (crbug.com/571146).
- callback.Run(mojo::String("fake auth code from ArcAuthService in Chrome"));
+ DCHECK(thread_checker_.CalledOnValidThread());
+ callback.Run(mojo::String(GetAndResetAutoCode()));
+}
+
+void ArcAuthService::SetState(State state) {
+ DCHECK_NE(state_, state);
+ state_ = state;
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_));
+}
+
+void ArcAuthService::OnPrimaryUserProfilePrepared(Profile* profile) {
+ DCHECK(profile && profile != profile_);
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ Shutdown();
+
+ profile_ = profile;
+
+ // TODO(khmel). At this moment UI to handle ARC OptIn is not ready yet. Assume
+ // we opted in by default. When UI is ready, this should be synced with
+ // user's prefs.
+ FetchAuthCode();
+}
+
+void ArcAuthService::Shutdown() {
+ profile_ = nullptr;
+ ArcBridgeService::Get()->Shutdown();
+ if (state_ != State::DISABLE) {
+ auth_fetcher_.reset();
+ SetState(State::DISABLE);
+ }
+}
+
+void ArcAuthService::AddObserver(Observer* observer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ observer_list_.AddObserver(observer);
+}
+
+void ArcAuthService::RemoveObserver(Observer* observer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ observer_list_.RemoveObserver(observer);
+}
+
+void ArcAuthService::CloseUI() {
+ if (auth_ui_) {
+ auth_ui_->Close();
+ DCHECK(!auth_ui_);
+ }
+}
+
+void ArcAuthService::SetAuthCodeAndStartArc(const std::string& auth_code) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!auth_code.empty());
+ DCHECK_NE(state_, State::ENABLE);
+
+ CloseUI();
+ auth_fetcher_.reset();
+ auth_code_ = auth_code;
+ ArcBridgeService::Get()->HandleStartup();
+
+ SetState(State::ENABLE);
+}
+
+void ArcAuthService::FetchAuthCode() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(state_, State::DISABLE);
+
+ CloseUI();
+ auth_code_.clear();
+
+ SetState(State::FETCHING_CODE);
+
+ auth_fetcher_.reset(new ArcAuthFetcher(profile_->GetRequestContext(), this));
+}
+
+void ArcAuthService::OnAuthCodeFetched(const std::string& auth_code) {
+ DCHECK_EQ(state_, State::FETCHING_CODE);
+ SetAuthCodeAndStartArc(auth_code);
+}
+
+void ArcAuthService::OnAuthCodeNeedUI() {
+ CloseUI();
+ if (!disable_ui_for_testing)
+ auth_ui_ = new ArcAuthUI(profile_, this);
+}
+
+void ArcAuthService::OnAuthCodeFailed() {
+ DCHECK_EQ(state_, State::FETCHING_CODE);
+ CloseUI();
+
+ SetState(State::NO_CODE);
+}
+
+void ArcAuthService::OnAuthUIClosed() {
+ DCHECK(auth_ui_);
+ auth_ui_ = nullptr;
+}
+
+std::ostream& operator<<(std::ostream& os, const ArcAuthService::State& state) {
+ switch (state) {
+ case ArcAuthService::State::DISABLE:
+ return os << kStateDisable;
+ case ArcAuthService::State::FETCHING_CODE:
+ return os << kStateFetchingCode;
+ case ArcAuthService::State::NO_CODE:
+ return os << kStateNoCode;
+ case ArcAuthService::State::ENABLE:
+ return os << kStateEnable;
+ default:
+ NOTREACHED();
+ return os;
+ }
}
} // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.h b/chrome/browser/chromeos/arc/arc_auth_service.h
index d14d2b1..6ed0d23 100644
--- a/chrome/browser/chromeos/arc/arc_auth_service.h
+++ b/chrome/browser/chromeos/arc/arc_auth_service.h
@@ -5,35 +5,105 @@
#ifndef CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_SERVICE_H_
#define CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_SERVICE_H_
+#include <ostream>
+
#include "base/macros.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+#include "chrome/browser/chromeos/arc/arc_auth_ui.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service.h"
+#include "components/arc/auth/arc_auth_fetcher.h"
#include "components/arc/common/auth.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
+class Profile;
+
namespace arc {
// This class proxies the request from the client to fetch an auth code from
// LSO.
class ArcAuthService : public ArcService,
public AuthHost,
- public ArcBridgeService::Observer {
+ public ArcBridgeService::Observer,
+ public ArcAuthFetcher::Delegate,
+ public ArcAuthUI::Delegate {
public:
+ enum class State {
+ DISABLE, // ARC is not allowed to run (default).
+ FETCHING_CODE, // ARC is allowed, receiving auth_2 code.
+ NO_CODE, // ARC is allowed, auth_2 code was not received.
+ ENABLE, // ARC is allowed, auth_2 code was received.
+ };
+
+ class Observer {
+ public:
+ virtual ~Observer() = default;
+
+ // Called whenever Opt-In state of the ARC has been changed.
+ virtual void OnOptInChanged(State state) = 0;
+ };
+
explicit ArcAuthService(ArcBridgeService* bridge_service);
~ArcAuthService() override;
- private:
- // Overrides ArcBridgeService::Observer.
+ static ArcAuthService* Get();
+
+ static void DisableUIForTesting();
+
+ void OnPrimaryUserProfilePrepared(Profile* profile);
+ void Shutdown();
+
+ State state() const { return state_; }
+
+ // Sets the auth code. Can be set from internally or from external component
+ // that accepts user's credentials. This actually starts ARC bridge service.
+ void SetAuthCodeAndStartArc(const std::string& auth_code);
+
+ std::string GetAndResetAutoCode();
+
+ // Adds or removes observers.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // ArcBridgeService::Observer:
void OnAuthInstanceReady() override;
- // Overrides AuthHost.
+ // Overrides AuthHost. For security reason this code can be used only
+ // once and exists for specific period of time.
void GetAuthCode(const GetAuthCodeCallback& callback) override;
+ // ArcAuthFetcher::Delegate:
+ void OnAuthCodeFetched(const std::string& auth_code) override;
+ void OnAuthCodeNeedUI() override;
+ void OnAuthCodeFailed() override;
+
+ // ArcAuthUI::Delegate:
+ void OnAuthUIClosed() override;
+
+ private:
+ void FetchAuthCode();
+ void CloseUI();
+ void SetState(State state);
+
+ // Unowned pointer. Keeps current profile.
+ Profile* profile_ = nullptr;
+
+ // Owned by view hierarchy.
+ ArcAuthUI* auth_ui_ = nullptr;
+
mojo::Binding<AuthHost> binding_;
+ base::ThreadChecker thread_checker_;
+ State state_ = State::DISABLE;
+ base::ObserverList<Observer> observer_list_;
+ scoped_ptr<ArcAuthFetcher> auth_fetcher_;
+ std::string auth_code_;
DISALLOW_COPY_AND_ASSIGN(ArcAuthService);
};
+std::ostream& operator<<(std::ostream& os, const ArcAuthService::State& state);
+
} // namespace arc
#endif // CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_SERVICE_H_
diff --git a/chrome/browser/chromeos/arc/arc_auth_service_unittest.cc b/chrome/browser/chromeos/arc/arc_auth_service_unittest.cc
new file mode 100644
index 0000000..599c17d
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_auth_service_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/arc/arc_auth_service.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/auth/arc_auth_fetcher.h"
+#include "components/arc/test/fake_arc_bridge_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_fetcher.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace arc {
+
+namespace {
+
+const int kThreadOptions = content::TestBrowserThreadBundle::IO_MAINLOOP;
+const char kTestAuthCode[] = "4/Qa3CPIhh-WcMfWSf9HZaYcGUhEeax-F9sQK9CNRhZWs";
+
+} // namespace
+
+class ArcAuthServiceTest : public testing::Test {
+ public:
+ ArcAuthServiceTest()
+ : thread_bundle_(new content::TestBrowserThreadBundle(kThreadOptions)),
+ url_fetcher_factory_(
+ nullptr,
+ base::Bind(&ArcAuthServiceTest::FakeURLFetcherCreator,
+ base::Unretained(this))) {}
+ ~ArcAuthServiceTest() override = default;
+
+ void SetUp() override {
+ ArcAuthService::DisableUIForTesting();
+
+ EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+ TestingProfile::Builder profile_builder;
+ profile_builder.SetPath(temp_dir_.path().AppendASCII("TestArcProfile"));
+
+ profile_ = profile_builder.Build();
+ bridge_service_.reset(new FakeArcBridgeService());
+ auth_service_.reset(new ArcAuthService(bridge_service_.get()));
+
+ // Check initial conditions.
+ EXPECT_EQ(bridge_service_.get(), ArcBridgeService::Get());
+ EXPECT_EQ(true, !ArcBridgeService::Get()->available());
+ EXPECT_EQ(ArcBridgeService::State::STOPPED,
+ ArcBridgeService::Get()->state());
+ }
+
+ void TearDown() override {}
+
+ protected:
+ Profile* profile() { return profile_.get(); }
+ FakeArcBridgeService* bridge_service() { return bridge_service_.get(); }
+ ArcAuthService* auth_service() { return auth_service_.get(); }
+ net::FakeURLFetcherFactory& url_fetcher_factory() {
+ return url_fetcher_factory_;
+ }
+ void set_cookie(const std::string& cookie) { rt_cookie_ = cookie; }
+
+ private:
+ scoped_ptr<net::FakeURLFetcher> FakeURLFetcherCreator(
+ const GURL& url,
+ net::URLFetcherDelegate* delegate,
+ const std::string& response_data,
+ net::HttpStatusCode response_code,
+ net::URLRequestStatus::Status status) {
+ scoped_ptr<net::FakeURLFetcher> fetcher(new net::FakeURLFetcher(
+ url, delegate, response_data, response_code, status));
+ // Use cookie only once.
+ if (!rt_cookie_.empty()) {
+ net::ResponseCookies cookies;
+ cookies.push_back(rt_cookie_);
+ fetcher->set_cookies(cookies);
+ rt_cookie_.clear();
+ }
+ return fetcher;
+ }
+
+ scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
+ net::FakeURLFetcherFactory url_fetcher_factory_;
+ scoped_ptr<arc::FakeArcBridgeService> bridge_service_;
+ scoped_ptr<arc::ArcAuthService> auth_service_;
+ scoped_ptr<TestingProfile> profile_;
+ base::ScopedTempDir temp_dir_;
+ std::string rt_cookie_;
+
+ DISALLOW_COPY_AND_ASSIGN(ArcAuthServiceTest);
+};
+
+TEST_F(ArcAuthServiceTest, Workflow) {
+ ASSERT_EQ(ArcBridgeService::State::STOPPED, bridge_service()->state());
+ ASSERT_EQ(ArcAuthService::State::DISABLE, auth_service()->state());
+ ASSERT_EQ(std::string(), auth_service()->GetAndResetAutoCode());
+
+ const GURL gaia_gurl = ArcAuthFetcher::CreateURL();
+ url_fetcher_factory().SetFakeResponse(gaia_gurl, std::string(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ std::string cookie = "oauth_code=";
+ cookie += kTestAuthCode;
+ cookie += "; Path=/o/oauth2/programmatic_auth; Secure; HttpOnly";
+ set_cookie(cookie);
+ auth_service()->OnPrimaryUserProfilePrepared(profile());
+
+ // Setting profile initiates a code fetching process.
+ ASSERT_EQ(ArcAuthService::State::FETCHING_CODE, auth_service()->state());
+
+ content::BrowserThread::GetBlockingPool()->FlushForTesting();
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(ArcAuthService::State::ENABLE, auth_service()->state());
+ ASSERT_EQ(ArcBridgeService::State::READY, bridge_service()->state());
+ // Auth code valid only for one call.
+ ASSERT_EQ(kTestAuthCode, auth_service()->GetAndResetAutoCode());
+ ASSERT_EQ(std::string(), auth_service()->GetAndResetAutoCode());
+
+ auth_service()->Shutdown();
+ ASSERT_EQ(ArcAuthService::State::DISABLE, auth_service()->state());
+ ASSERT_EQ(ArcBridgeService::State::STOPPED, bridge_service()->state());
+ ASSERT_EQ(std::string(), auth_service()->GetAndResetAutoCode());
+
+ // Send profile and don't provide a code.
+ auth_service()->OnPrimaryUserProfilePrepared(profile());
+
+ // Setting profile initiates a code fetching process.
+ ASSERT_EQ(ArcAuthService::State::FETCHING_CODE, auth_service()->state());
+
+ content::BrowserThread::GetBlockingPool()->FlushForTesting();
+ base::RunLoop().RunUntilIdle();
+
+ // UI is disabled in unit tests and this code is unchanged.
+ ASSERT_EQ(ArcAuthService::State::FETCHING_CODE, auth_service()->state());
+
+ // Send error response.
+ url_fetcher_factory().SetFakeResponse(gaia_gurl, std::string(),
+ net::HTTP_BAD_REQUEST,
+ net::URLRequestStatus::SUCCESS);
+ auth_service()->Shutdown();
+ ASSERT_EQ(ArcAuthService::State::DISABLE, auth_service()->state());
+ auth_service()->OnPrimaryUserProfilePrepared(profile());
+
+ ASSERT_EQ(ArcAuthService::State::FETCHING_CODE, auth_service()->state());
+ content::BrowserThread::GetBlockingPool()->FlushForTesting();
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(ArcAuthService::State::NO_CODE, auth_service()->state());
+}
+
+} // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_auth_ui.cc b/chrome/browser/chromeos/arc/arc_auth_ui.cc
new file mode 100644
index 0000000..6bbd157
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_auth_ui.cc
@@ -0,0 +1,108 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/arc_auth_ui.h"
+
+#include "chrome/browser/chromeos/arc/arc_auth_service.h"
+#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/load_states.h"
+#include "ui/views/controls/webview/web_dialog_view.h"
+#include "ui/views/widget/widget.h"
+
+namespace arc {
+
+namespace {
+
+const int kDefaultWidth = 480;
+const int kDefaultHeight = 640;
+
+} // namespace
+
+ArcAuthUI::ArcAuthUI(content::BrowserContext* browser_context,
+ Delegate* delegate)
+ : browser_context_(browser_context),
+ delegate_(delegate),
+ target_url_(ArcAuthFetcher::CreateURL()) {
+ DCHECK(browser_context_ && delegate_);
+ views::WebDialogView* view = new views::WebDialogView(
+ browser_context_, this, new ChromeWebContentsHandler);
+ widget_ = views::Widget::CreateWindow(view);
+ widget_->Show();
+}
+
+ArcAuthUI::~ArcAuthUI() {}
+
+void ArcAuthUI::Close() {
+ widget_->CloseNow();
+}
+
+ui::ModalType ArcAuthUI::GetDialogModalType() const {
+ return ui::MODAL_TYPE_SYSTEM;
+}
+
+base::string16 ArcAuthUI::GetDialogTitle() const {
+ return base::string16();
+}
+
+GURL ArcAuthUI::GetDialogContentURL() const {
+ return target_url_;
+}
+
+void ArcAuthUI::GetWebUIMessageHandlers(
+ std::vector<content::WebUIMessageHandler*>* handlers) const {}
+
+void ArcAuthUI::GetDialogSize(gfx::Size* size) const {
+ size->SetSize(kDefaultWidth, kDefaultHeight);
+}
+
+std::string ArcAuthUI::GetDialogArgs() const {
+ return std::string();
+}
+
+void ArcAuthUI::OnDialogClosed(const std::string& json_retval) {
+ delegate_->OnAuthUIClosed();
+ delete this;
+}
+
+void ArcAuthUI::OnCloseContents(content::WebContents* source,
+ bool* out_close_dialog) {
+ *out_close_dialog = true;
+}
+
+bool ArcAuthUI::ShouldShowDialogTitle() const {
+ return false;
+}
+
+bool ArcAuthUI::HandleContextMenu(const content::ContextMenuParams& params) {
+ // Disable context menu.
+ return true;
+}
+
+void ArcAuthUI::OnLoadingStateChanged(content::WebContents* source) {
+ if (source->IsLoading())
+ return;
+
+ // Check if current page may contain required cookies and skip intermediate
+ // steps.
+ const GURL& current_url = source->GetVisibleURL();
+ if (target_url_.GetOrigin() != current_url.GetOrigin() ||
+ target_url_.path() != current_url.path()) {
+ return;
+ }
+
+ auth_fetcher_.reset(
+ new ArcAuthFetcher(browser_context_->GetRequestContext(), this));
+}
+
+void ArcAuthUI::OnAuthCodeFetched(const std::string& auth_code) {
+ ArcAuthService::Get()->SetAuthCodeAndStartArc(auth_code);
+}
+
+void ArcAuthUI::OnAuthCodeNeedUI() {}
+
+void ArcAuthUI::OnAuthCodeFailed() {}
+
+} // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_auth_ui.h b/chrome/browser/chromeos/arc/arc_auth_ui.h
new file mode 100644
index 0000000..7e810dc
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_auth_ui.h
@@ -0,0 +1,76 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_UI_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_UI_H_
+
+#include "base/macros.h"
+#include "components/arc/auth/arc_auth_fetcher.h"
+#include "ui/web_dialogs/web_dialog_delegate.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace views {
+class Widget;
+}
+
+namespace arc {
+
+// Shows ARC LSO web view that requires user input.
+class ArcAuthUI : public ui::WebDialogDelegate,
+ public ArcAuthFetcher::Delegate {
+ public:
+ class Delegate {
+ public:
+ // Called when dialog is closed.
+ virtual void OnAuthUIClosed() = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ ArcAuthUI(content::BrowserContext* browser_context, Delegate* delegate);
+ ~ArcAuthUI() override;
+
+ void Close();
+
+ // ui::WebDialogDelegate:
+ ui::ModalType GetDialogModalType() const override;
+ base::string16 GetDialogTitle() const override;
+ GURL GetDialogContentURL() const override;
+ void GetWebUIMessageHandlers(
+ std::vector<content::WebUIMessageHandler*>* handlers) const override;
+ void GetDialogSize(gfx::Size* size) const override;
+ std::string GetDialogArgs() const override;
+ void OnDialogClosed(const std::string& json_retval) override;
+ void OnCloseContents(content::WebContents* source,
+ bool* out_close_dialog) override;
+ bool ShouldShowDialogTitle() const override;
+ bool HandleContextMenu(const content::ContextMenuParams& params) override;
+ void OnLoadingStateChanged(content::WebContents* source) override;
+
+ // ArcAuthFetcher::Delegate:
+ void OnAuthCodeFetched(const std::string& code) override;
+ void OnAuthCodeNeedUI() override;
+ void OnAuthCodeFailed() override;
+
+ private:
+ // Unowned pointers.
+ content::BrowserContext* const browser_context_;
+ Delegate* const delegate_;
+ const GURL target_url_;
+
+ // Owned by view hierarchy.
+ views::Widget* widget_;
+
+ scoped_ptr<ArcAuthFetcher> auth_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(ArcAuthUI);
+};
+
+} // namespace arc
+
+#endif // CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_UI_H_
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 305ff99..e622102 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -33,6 +33,7 @@
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
+#include "chrome/browser/chromeos/arc/arc_auth_service.h"
#include "chrome/browser/chromeos/base/locale_util.h"
#include "chrome/browser/chromeos/boot_times_recorder.h"
#include "chrome/browser/chromeos/first_run/first_run.h"
@@ -1145,6 +1146,7 @@ void UserSessionManager::FinalizePrepareProfile(Profile* profile) {
DCHECK(arc::ArcServiceManager::Get());
arc::ArcServiceManager::Get()->OnPrimaryUserProfilePrepared(
multi_user_util::GetAccountIdFromProfile(profile));
+ arc::ArcAuthService::Get()->OnPrimaryUserProfilePrepared(profile);
}
}
@@ -1785,6 +1787,11 @@ bool UserSessionManager::TokenHandlesEnabled() {
}
void UserSessionManager::Shutdown() {
+ if (arc::ArcBridgeService::GetEnabled(
+ base::CommandLine::ForCurrentProcess())) {
+ DCHECK(arc::ArcServiceManager::Get());
+ arc::ArcAuthService::Get()->Shutdown();
+ }
token_handle_fetcher_.reset();
token_handle_util_.reset();
first_run::GoodiesDisplayer::Delete();
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index c3caca1..5b74f92 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -18,10 +18,6 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#if defined(OS_CHROMEOS)
-#include "ash/shell_observer.h"
-#endif
-
class Browser;
namespace ash {
@@ -92,21 +88,6 @@ class ChromeShellDelegate : public ash::ShellDelegate,
const content::NotificationDetails& details) override;
private:
-#if defined(OS_CHROMEOS)
- // An Observer to track session state and start/stop ARC accordingly.
- class ArcSessionObserver : public ash::ShellObserver {
- public:
- ArcSessionObserver();
- ~ArcSessionObserver() override;
-
- // ash::ShellObserver overrides:
- void OnLoginStateChanged(ash::user::LoginStatus status) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ArcSessionObserver);
- };
-#endif
-
void PlatformInit();
static ChromeShellDelegate* instance_;
@@ -124,9 +105,6 @@ class ChromeShellDelegate : public ash::ShellDelegate,
#if defined(OS_CHROMEOS)
scoped_ptr<chromeos::DisplayConfigurationObserver>
display_configuration_observer_;
-
- // An Observer to track session state and start/stop ARC accordingly.
- scoped_ptr<ArcSessionObserver> arc_session_observer_;
#endif
DISALLOW_COPY_AND_ASSIGN(ChromeShellDelegate);
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
index 08d97c4..23090c5 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
@@ -37,8 +37,6 @@
#include "chrome/browser/ui/browser_window.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/chromeos_switches.h"
-#include "components/arc/arc_bridge_service.h"
-#include "components/arc/arc_service_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/user_metrics.h"
#include "ui/aura/window.h"
@@ -231,18 +229,12 @@ void ChromeShellDelegate::PreInit() {
display_configuration_observer_.reset(
new chromeos::DisplayConfigurationObserver());
- arc_session_observer_.reset(new ArcSessionObserver);
-
chrome_user_metrics_recorder_.reset(new ChromeUserMetricsRecorder);
}
void ChromeShellDelegate::PreShutdown() {
display_configuration_observer_.reset();
- // Remove the ARC observer now since it uses the ash::Shell instance in its
- // destructor, which is unavailable after PreShutdown() returns.
- arc_session_observer_.reset();
-
chrome_user_metrics_recorder_.reset();
}
@@ -310,35 +302,3 @@ void ChromeShellDelegate::PlatformInit() {
chrome::NOTIFICATION_SESSION_STARTED,
content::NotificationService::AllSources());
}
-
-ChromeShellDelegate::ArcSessionObserver::ArcSessionObserver() {
- ash::Shell::GetInstance()->AddShellObserver(this);
-}
-
-ChromeShellDelegate::ArcSessionObserver::~ArcSessionObserver() {
- ash::Shell::GetInstance()->RemoveShellObserver(this);
-}
-
-void ChromeShellDelegate::ArcSessionObserver::OnLoginStateChanged(
- ash::user::LoginStatus status) {
- switch (status) {
- case ash::user::LOGGED_IN_LOCKED:
- case ash::user::LOGGED_IN_KIOSK_APP:
- return;
-
- case ash::user::LOGGED_IN_NONE:
- arc::ArcServiceManager::Get()->arc_bridge_service()->Shutdown();
- break;
-
- case ash::user::LOGGED_IN_USER:
- case ash::user::LOGGED_IN_OWNER:
- case ash::user::LOGGED_IN_GUEST:
- case ash::user::LOGGED_IN_PUBLIC:
- case ash::user::LOGGED_IN_SUPERVISED:
- if (arc::ArcBridgeService::GetEnabled(
- base::CommandLine::ForCurrentProcess())) {
- arc::ArcServiceManager::Get()->arc_bridge_service()->HandleStartup();
- }
- break;
- }
-}
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 7720c68..b455d55 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -54,6 +54,8 @@
'browser/chromeos/app_mode/startup_app_launcher.h',
'browser/chromeos/arc/arc_auth_service.cc',
'browser/chromeos/arc/arc_auth_service.h',
+ 'browser/chromeos/arc/arc_auth_ui.cc',
+ 'browser/chromeos/arc/arc_auth_ui.h',
'browser/chromeos/arc/arc_intent_helper_bridge.cc',
'browser/chromeos/arc/arc_intent_helper_bridge.h',
'browser/chromeos/arc/settings_bridge.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 03aa18b..4b9f2ee 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1645,7 +1645,8 @@
'chrome_unit_tests_app_list_chromeos_arc_sources': [
'browser/ui/app_list/arc/arc_app_unittest.cc',
],
- 'chrome_unit_tests_arc_settings_bridge_sources': [
+ 'chrome_unit_tests_arc_sources': [
+ 'browser/chromeos/arc/arc_auth_service_unittest.cc',
'browser/chromeos/arc/settings_bridge_unittest.cc',
],
# Sources for Offline pages. For now only for Android.
@@ -2800,7 +2801,7 @@
],
}],
['chromeos==1', {
- 'sources': [ '<@(chrome_unit_tests_arc_settings_bridge_sources)' ],
+ 'sources': [ '<@(chrome_unit_tests_arc_sources)' ],
'dependencies': [
'../components/components.gyp:arc_test_support',
],