Commit 21994dac authored by Alice Gong's avatar Alice Gong Committed by Chromium LUCI CQ

Implement OAuth2 authentication flow for Box to obtain authorization, refresh...

Implement OAuth2 authentication flow for Box to obtain authorization, refresh token, and access token using a pop-up window, and store
tokens into profile prefs.

This is part of a series that will eventually, if enabled by
enterprise admin, replace regular DownloadItemRenameHandler with
FileSystemConnectorRenameHandler, which uses FileSystemConnector to
redirect downloaded local temporary files to get uploaded through a
series of BoxApiCallFlow steps.

This CL does the following:

1/ Create new profile prefs to hold the OAuth2 tokens needed for file
system connectors. (connectors/connectors_prefs.h/cc)
2/ Implement UX for gathering Box user consent. This is being
implemented as pop-up window hosting the Box consent flow, much like
the force sign in dialog hosts the Google sign in flow. (connectors/
file_system/signin_dialog_delegate.h/cc)
3/ Implement OAuth2 flow to mint access and refresh tokens from user
consent’s auth_code.
4/ Implement OAuth2 flow to mint access and refresh tokens from the
previous refresh token. (connectors/file_system/
box_access_token_fetcher.h/cc)

BUG=1168607

Change-Id: If4882440315151a7cc23f2a6f56430bdb2bc09bf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2591667
Commit-Queue: Alice Gong <alicego@google.com>
Auto-Submit: Alice Gong <alicego@google.com>
Reviewed-by: default avatarNicolas Ouellet-Payeur <nicolaso@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarRoger Tawa <rogerta@chromium.org>
Reviewed-by: default avatarMarc-André Decoste <mad@chromium.org>
Reviewed-by: default avatarDominique Fauteux-Chapleau <domfc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#846300}
parent abcfd145
......@@ -3571,10 +3571,16 @@ static_library("browser") {
"enterprise/connectors/content_analysis_dialog.h",
"enterprise/connectors/enterprise_connectors_policy_handler.cc",
"enterprise/connectors/enterprise_connectors_policy_handler.h",
"enterprise/connectors/file_system/authorization_client_info.cc",
"enterprise/connectors/file_system/authorization_client_info.h",
"enterprise/connectors/file_system/box_access_token_fetcher.cc",
"enterprise/connectors/file_system/box_access_token_fetcher.h",
"enterprise/connectors/file_system/box_api_call_endpoints.cc",
"enterprise/connectors/file_system/box_api_call_endpoints.h",
"enterprise/connectors/file_system/box_api_call_flow.cc",
"enterprise/connectors/file_system/box_api_call_flow.h",
"enterprise/connectors/file_system/signin_dialog_delegate.cc",
"enterprise/connectors/file_system/signin_dialog_delegate.h",
"enterprise/connectors/reporting_service_settings.cc",
"enterprise/connectors/reporting_service_settings.h",
"enterprise/connectors/service_provider_config.cc",
......
......@@ -25,6 +25,12 @@ const char kOnBulkDataEntryScopePref[] =
const char kOnSecurityEventScopePref[] =
"enterprise_connectors.scope.on_security_event";
const char kFileSystemBoxAccessTokenPref[] =
"enterprise_connectors.file_system.box.access_token";
const char kFileSystemBoxRefreshTokenPref[] =
"enterprise_connectors.file_system.box.refresh_token";
void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(kOnFileAttachedPref);
registry->RegisterListPref(kOnFileDownloadedPref);
......@@ -34,6 +40,9 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(kOnFileDownloadedScopePref, 0);
registry->RegisterIntegerPref(kOnBulkDataEntryScopePref, 0);
registry->RegisterIntegerPref(kOnSecurityEventScopePref, 0);
registry->RegisterStringPref(kFileSystemBoxAccessTokenPref, std::string());
registry->RegisterStringPref(kFileSystemBoxRefreshTokenPref, std::string());
// TODO(1157641) store folder_id in profile pref to handle indexing latency.
}
} // namespace enterprise_connectors
......@@ -28,6 +28,11 @@ extern const char kOnFileDownloadedScopePref[];
extern const char kOnBulkDataEntryScopePref[];
extern const char kOnSecurityEventScopePref[];
// Prefs used by the FileSystem Connector to store OAuth2 Tokens for accessing
// the APIs the connector talks to.
extern const char kFileSystemBoxAccessTokenPref[];
extern const char kFileSystemBoxRefreshTokenPref[];
void RegisterProfilePrefs(PrefRegistrySimple* registry);
} // namespace enterprise_connectors
......
// Copyright 2021 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/enterprise/connectors/file_system/authorization_client_info.h"
namespace enterprise_connectors {
const char kFileSystemClientId[] = "dummy_id";
const char kFileSystemClientSecret[] = "dummy_secret";
// TODO(https://crbug.com/1157627): move them into policy/config.
// Currently, values are to be overridden on local builds.
} // namespace enterprise_connectors
// Copyright 2021 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_ENTERPRISE_CONNECTORS_FILE_SYSTEM_AUTHORIZATION_CLIENT_INFO_H_
#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_AUTHORIZATION_CLIENT_INFO_H_
namespace enterprise_connectors {
// OAuth2 client info for the FileSystem Connector; tokens are stored in
// connectors_prefs.h/cc
extern const char kFileSystemClientId[];
extern const char kFileSystemClientSecret[];
} // namespace enterprise_connectors
#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_AUTHORIZATION_CLIENT_INFO_H_
// Copyright 2021 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/enterprise/connectors/file_system/box_access_token_fetcher.h"
#include "chrome/browser/enterprise/connectors/connectors_prefs.h"
#include "chrome/browser/enterprise/connectors/file_system/box_api_call_endpoints.h"
#include "google_apis/gaia/google_service_auth_error.h"
namespace enterprise_connectors {
BoxAccessTokenFetcher::BoxAccessTokenFetcher(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& refresh_token,
const std::string& auth_code,
TokenCallback callback)
: OAuth2AccessTokenFetcherImpl(this,
url_loader_factory,
refresh_token,
auth_code),
callback_(std::move(callback)) {}
BoxAccessTokenFetcher::~BoxAccessTokenFetcher() = default;
GURL BoxAccessTokenFetcher::GetAccessTokenURL() const {
return GURL(kFileSystemBoxEndpointOAuth2Token);
}
net::NetworkTrafficAnnotationTag
BoxAccessTokenFetcher::GetTrafficAnnotationTag() const {
return net::DefineNetworkTrafficAnnotation("box_access_token_fetcher",
R"(
semantics {
sender: "OAuth 2.0 Access Token Fetcher"
description:
"This request is used by the Box integration to fetch an OAuth 2.0 "
"access token for a known Box account."
trigger:
"This request can be triggered when the user uploads or downloads "
"a file."
data:
"Chrome OAuth 2.0 client id and secret, the set of OAuth 2.0 "
"scopes and the OAuth 2.0 refresh token."
destination: OTHER
}
policy {
cookies_allowed: NO
setting:
"This feature cannot be disabled in settings. It is disabled by "
"default, unless the administrator enables it via policy."
policy_exception_justification: "Not implemented yet."
})");
// TODO(https://crbug.com/1167934): Add enterprise policy.
// e.g., FileSystemEnterpriseConnector {policy_options {mode: MANDATORY}}
}
void BoxAccessTokenFetcher::OnGetTokenSuccess(
const TokenResponse& token_response) {
std::move(callback_).Run(true, token_response.access_token,
token_response.refresh_token);
}
void BoxAccessTokenFetcher::OnGetTokenFailure(
const GoogleServiceAuthError& error) {
// TODO(https://crbug.com/1159179): pop a box about authentication failure?
DLOG(ERROR) << "[BoxAccessTokenFetcher] Failed: " << error.error_message();
std::move(callback_).Run(false, std::string(), std::string());
}
void SetFileSystemOAuth2Tokens(PrefService* prefs,
const std::string& service_provider,
const std::string& access_token,
const std::string& refresh_token) {
std::string pref_path = base::StringPrintf(
"enterprise_connectors.file_system.%s.", service_provider.c_str());
prefs->SetString(pref_path + "access_token", access_token);
prefs->SetString(pref_path + "refresh_token", refresh_token);
}
} // namespace enterprise_connectors
// Copyright 2021 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_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_ACCESS_TOKEN_FETCHER_H_
#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_ACCESS_TOKEN_FETCHER_H_
#include "base/callback.h"
#include "components/prefs/pref_service.h"
#include "google_apis/gaia/oauth2_access_token_consumer.h"
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace enterprise_connectors {
// Helper class to retrieve a Box access token.
// Notes on lifetime:
// - When used by FileSystemSigninDialogDelegate, ShowDialog() blocks, which
// ensures this class is alive, until the entire authentication (including this
// class) process is completed.
// - In event of termination of browser/tab, the URLLoader in base class is
// safely deletable, even while it's invoking any callback method passed to it.
class BoxAccessTokenFetcher : public OAuth2AccessTokenFetcherImpl,
public OAuth2AccessTokenConsumer {
public:
// Used in OnGetTokenSuccess/Failure; arguments are access_token and
// refresh_token.
using TokenCallback =
base::OnceCallback<void(bool, const std::string&, const std::string&)>;
BoxAccessTokenFetcher(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& refresh_token,
const std::string& auth_code,
TokenCallback callback);
~BoxAccessTokenFetcher() override;
// The methods are protected for testing purposes only.
protected:
// OAuth2AccessTokenFetcherImpl interface.
GURL GetAccessTokenURL() const override;
net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag() const override;
// OAuth2AccessTokenConsumer interface.
void OnGetTokenSuccess(const TokenResponse& token_response) override;
void OnGetTokenFailure(const GoogleServiceAuthError& error) override;
private:
TokenCallback callback_;
};
void SetFileSystemOAuth2Tokens(PrefService* prefs,
const std::string& service_provider,
const std::string& access_token,
const std::string& refresh_token);
} // namespace enterprise_connectors
#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_ACCESS_TOKEN_FETCHER_H_
// Copyright 2020 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/enterprise/connectors/file_system/box_access_token_fetcher.h"
#include <memory>
#include "chrome/browser/enterprise/connectors/connectors_prefs.h"
#include "chrome/browser/enterprise/connectors/file_system/box_api_call_endpoints.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/browser_task_environment.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace enterprise_connectors {
TEST(SetGetFileSystemOAuth2Token, Box) {
content::BrowserTaskEnvironment task_environment;
TestingProfile profile;
PrefService* prefs = profile.GetPrefs();
SetFileSystemOAuth2Tokens(prefs, "box", "testAToken", "testRToken");
EXPECT_TRUE(prefs->HasPrefPath(kFileSystemBoxAccessTokenPref));
EXPECT_TRUE(prefs->HasPrefPath(kFileSystemBoxRefreshTokenPref));
EXPECT_EQ(prefs->GetString(kFileSystemBoxAccessTokenPref), "testAToken");
EXPECT_EQ(prefs->GetString(kFileSystemBoxRefreshTokenPref), "testRToken");
}
class BoxAccessTokenFetcherForTest : public BoxAccessTokenFetcher {
public:
using BoxAccessTokenFetcher::BoxAccessTokenFetcher;
using BoxAccessTokenFetcher::GetAccessTokenURL;
using BoxAccessTokenFetcher::OnGetTokenFailure;
using BoxAccessTokenFetcher::OnGetTokenSuccess;
private:
DISALLOW_COPY_AND_ASSIGN(BoxAccessTokenFetcherForTest);
};
class BoxAccessTokenFetcherTest : public testing::Test {
protected:
void SetUp() override {
fetcher_ = std::make_unique<BoxAccessTokenFetcherForTest>(
url_loader_factory_.GetSafeWeakWrapper(), // dummy; not for unit tests.
"refresh token", "", // use existing refresh token to get access token.
base::BindOnce(&BoxAccessTokenFetcherTest::OnResponse,
factory_.GetWeakPtr()));
}
void OnResponse(bool success,
const std::string& access_token,
const std::string& refresh_token) {
fetch_success_ = success;
access_token_fetched_ = access_token;
refresh_token_fetched_ = refresh_token;
}
OAuth2AccessTokenConsumer::TokenResponse MakeTokenResponse(
const std::string& access_token,
const std::string& refresh_token) {
OAuth2AccessTokenConsumer::TokenResponse::Builder builder;
builder.WithAccessToken(access_token);
builder.WithRefreshToken(refresh_token);
builder.WithExpirationTime(base::Time::Now() +
base::TimeDelta::FromDays(1));
builder.WithIdToken("id token");
return builder.build();
}
std::unique_ptr<BoxAccessTokenFetcherForTest> fetcher_;
bool fetch_success_ = false;
std::string access_token_fetched_ = "defaultAToken";
std::string refresh_token_fetched_ = "defaultRToken";
network::TestURLLoaderFactory url_loader_factory_;
base::WeakPtrFactory<BoxAccessTokenFetcherTest> factory_{this};
};
TEST_F(BoxAccessTokenFetcherTest, URL) {
ASSERT_EQ(fetcher_->GetAccessTokenURL(), kFileSystemBoxEndpointOAuth2Token);
}
TEST_F(BoxAccessTokenFetcherTest, Success) {
auto token_response = MakeTokenResponse("goodAToken", "goodRToken");
fetcher_->OnGetTokenSuccess(token_response);
ASSERT_TRUE(fetch_success_);
ASSERT_EQ(access_token_fetched_, "goodAToken");
ASSERT_EQ(refresh_token_fetched_, "goodRToken");
}
TEST_F(BoxAccessTokenFetcherTest, Failure) {
auto error = GoogleServiceAuthError::FromConnectionError(1);
fetcher_->OnGetTokenFailure(error);
ASSERT_FALSE(fetch_success_);
ASSERT_TRUE(access_token_fetched_.empty()) << access_token_fetched_;
ASSERT_TRUE(refresh_token_fetched_.empty()) << refresh_token_fetched_;
}
} // namespace enterprise_connectors
......@@ -6,6 +6,10 @@
namespace enterprise_connectors {
const char kFileSystemBoxEndpointApi[] = "https://api.box.com/";
const char kFileSystemBoxEndpointOAuth2Authorization[] =
"https://account.box.com/api/oauth2/authorize/?client_id";
const char kFileSystemBoxEndpointOAuth2Token[] =
"https://api.box.com/oauth2/token";
const char kFileSystemBoxEndpointWholeFileUpload[] =
"https://upload.box.com/api/2.0/files/content";
} // namespace enterprise_connectors
......@@ -7,6 +7,8 @@
namespace enterprise_connectors {
extern const char kFileSystemBoxEndpointApi[];
extern const char kFileSystemBoxEndpointOAuth2Authorization[];
extern const char kFileSystemBoxEndpointOAuth2Token[];
extern const char kFileSystemBoxEndpointWholeFileUpload[];
} // namespace enterprise_connectors
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Copyright 2021 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.
//
......
// Copyright 2021 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/enterprise/connectors/file_system/signin_dialog_delegate.h"
#include <utility>
#include <vector>
#include "base/optional.h"
#include "chrome/browser/enterprise/connectors/file_system/authorization_client_info.h"
#include "chrome/browser/enterprise/connectors/file_system/box_access_token_fetcher.h"
#include "chrome/browser/enterprise/connectors/file_system/box_api_call_endpoints.h"
#include "chrome/grit/generated_resources.h"
#include "components/prefs/pref_service.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/download_item_utils.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/storage_partition.h"
#include "google_apis/gaia/oauth2_access_token_consumer.h"
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#include "google_apis/gaia/oauth2_api_call_flow.h"
#include "net/base/url_util.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "ui/views/layout/fill_layout.h"
#include "url/gurl.h"
namespace {
// The OAuth2 configuration of the Box App used for the file system integration
// uses https://google.com/generate_204 as the redirect URI.
// This URI is used because:
// 1/ Chrome is a native app and does not otherwise have an app URI to
// redirect to.
// 2/ An HTTP 204 response is optimal because it is a success.
// 3/ An HTTP 204 response is optimal because it is the smallest
// response that can be generated (it has no body).
// 4/ This URI is used by other native apps for the same purpose.
// 5/ It is controlled by Google.
bool IsOAuth2RedirectURI(const GURL& url) {
return url.host() == "google.com" && url.path() == "/generate_204";
}
} // namespace
namespace enterprise_connectors {
////// Authorization Dialog ///////////////////////////////////////////////////
FileSystemSigninDialogDelegate::FileSystemSigninDialogDelegate(
content::BrowserContext* browser_context,
AuthorizationCompletedCallback callback)
: web_view_(std::make_unique<views::WebView>(browser_context)),
callback_(std::move(callback)) {
SetHasWindowSizeControls(true);
SetTitle(IDS_PROFILES_GAIA_SIGNIN_TITLE);
SetButtons(ui::DIALOG_BUTTON_NONE);
// TODO(https://crbug.com/1158490): Add a way to cancel user login.
set_use_custom_frame(false);
AddChildView(web_view_.get());
SetLayoutManager(std::make_unique<views::FillLayout>());
web_modal::WebContentsModalDialogManager::CreateForWebContents(
web_view_->GetWebContents());
web_modal::WebContentsModalDialogManager::FromWebContents(
web_view_->GetWebContents())
->SetDelegate(this);
Observe(web_view_->GetWebContents());
// TODO(https://crbug.com/1160015): pass in URL as arg and get from service
// provider config.
std::string url(kFileSystemBoxEndpointOAuth2Authorization);
url.append(kFileSystemClientId);
url.append("&response_type=code");
web_view_->LoadInitialURL(GURL(url));
}
FileSystemSigninDialogDelegate::~FileSystemSigninDialogDelegate() = default;
// static
void FileSystemSigninDialogDelegate::ShowDialog(
content::WebContents* web_contents,
AuthorizationCompletedCallback callback) {
content::BrowserContext* browser_context = web_contents->GetBrowserContext();
gfx::NativeView parent = web_contents->GetNativeView();
FileSystemSigninDialogDelegate* delegate =
new FileSystemSigninDialogDelegate(browser_context, std::move(callback));
// Object will be deleted internally by widget via DeleteDelegate().
// TODO(https://crbug.com/1160012): use std::unique_ptr instead?
views::DialogDelegate::CreateDialogWidget(delegate, nullptr, parent);
delegate->GetWidget()->Show();
// This only returns when the dialog is closed.
}
web_modal::WebContentsModalDialogHost*
FileSystemSigninDialogDelegate::GetWebContentsModalDialogHost() {
return this;
}
gfx::NativeView FileSystemSigninDialogDelegate::GetHostView() const {
return GetWidget()->GetNativeView();
}
gfx::Point FileSystemSigninDialogDelegate::GetDialogPosition(
const gfx::Size& size) {
gfx::Size widget_size = GetWidget()->GetWindowBoundsInScreen().size();
return gfx::Point(std::max(0, (widget_size.width() - size.width()) / 2),
std::max(0, (widget_size.height() - size.height()) / 2));
}
gfx::Size FileSystemSigninDialogDelegate::GetMaximumDialogSize() {
return GetWidget()->GetWindowBoundsInScreen().size();
}
void FileSystemSigninDialogDelegate::AddObserver(
web_modal::ModalDialogHostObserver* observer) {}
void FileSystemSigninDialogDelegate::RemoveObserver(
web_modal::ModalDialogHostObserver* observer) {}
// views::DialogDelegate:
gfx::Size FileSystemSigninDialogDelegate::CalculatePreferredSize() const {
// TODO(https://crbug.com/1159213): need to tweak this; box sign in/consent
// page changes size.
return gfx::Size(800, 640);
}
ui::ModalType FileSystemSigninDialogDelegate::GetModalType() const {
return ui::MODAL_TYPE_WINDOW;
}
void FileSystemSigninDialogDelegate::DeleteDelegate() {
delete this;
}
views::View* FileSystemSigninDialogDelegate::GetInitiallyFocusedView() {
return static_cast<views::View*>(web_view_.get());
}
void FileSystemSigninDialogDelegate::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
const GURL& url = navigation_handle->GetURL();
if (!IsOAuth2RedirectURI(url)) {
return;
}
std::string auth_code;
// Look for the auth_code. It is found in the code= URL parameter.
if (!net::GetValueForKeyInQuery(url, "code", &auth_code)) {
DLOG(ERROR) << "Failed to extract authorization code from url: " << url;
// TODO(https://crbug.com/1159179): pop a box about authentication failure?
return;
}
content::StoragePartition* partition =
content::BrowserContext::GetStoragePartitionForSite(
web_view_->GetBrowserContext(), GURL(kFileSystemBoxEndpointApi));
auto url_loader = partition->GetURLLoaderFactoryForBrowserProcess();
auto callback = base::BindOnce(
&FileSystemSigninDialogDelegate::OnGotOAuthTokens, factory_.GetWeakPtr());
// No refresh_token, so need to get both tokens with authorization code.
token_fetcher_ = std::make_unique<BoxAccessTokenFetcher>(
url_loader, std::string(), auth_code, std::move(callback));
token_fetcher_->Start(kFileSystemClientId, kFileSystemClientSecret,
std::vector<std::string>()); // No scope needed.
}
void FileSystemSigninDialogDelegate::OnGotOAuthTokens(
bool success,
const std::string& access_token,
const std::string& refresh_token) {
PrefService* prefs =
Profile::FromBrowserContext(web_view_->GetBrowserContext())->GetPrefs();
SetFileSystemOAuth2Tokens(prefs, "box", access_token, refresh_token);
token_fetcher_ = nullptr;
std::move(callback_).Run(success);
GetWidget()->Close();
}
// TODO(https://crbug.com/1159185): add browser_tests for this delegate.
} // namespace enterprise_connectors
// Copyright 2021 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_ENTERPRISE_CONNECTORS_FILE_SYSTEM_SIGNIN_DIALOG_DELEGATE_H_
#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_SIGNIN_DIALOG_DELEGATE_H_
#include "chrome/browser/enterprise/connectors/connectors_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
#include "components/download/public/common/download_item_impl.h"
#include "components/web_modal/web_contents_modal_dialog_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/window/dialog_delegate.h"
namespace enterprise_connectors {
// Helper class used by FileSystemRenameHandler to show a sign-in diaglog of Box
// to obtain authorization when there is no valid refresh token.
class FileSystemSigninDialogDelegate
: public views::DialogDelegateView,
public ChromeWebModalDialogManagerDelegate,
public web_modal::WebContentsModalDialogHost,
public content::WebContentsObserver {
public:
// Called with success or failure of this authorization attempt.
using AuthorizationCompletedCallback = base::OnceCallback<void(bool)>;
~FileSystemSigninDialogDelegate() override;
static void ShowDialog(content::WebContents* web_contents,
AuthorizationCompletedCallback callback);
private:
FileSystemSigninDialogDelegate(content::BrowserContext* browser_context,
AuthorizationCompletedCallback callback);
// ChromeWebModalDialogManagerDelegate:
web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost()
override;
// web_modal::WebContentsModalDialogHost:
gfx::NativeView GetHostView() const override;
gfx::Point GetDialogPosition(const gfx::Size& size) override;
gfx::Size GetMaximumDialogSize() override;
void AddObserver(web_modal::ModalDialogHostObserver* observer) override;
void RemoveObserver(web_modal::ModalDialogHostObserver* observer) override;
// views::DialogDelegate:
gfx::Size CalculatePreferredSize() const override;
ui::ModalType GetModalType() const override;
void DeleteDelegate() override;
views::View* GetInitiallyFocusedView() override;
// content::WebContentsObserver:
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void OnGotOAuthTokens(bool success,
const std::string& access_token,
const std::string& refresh_token);
std::unique_ptr<views::WebView> web_view_;
std::unique_ptr<OAuth2AccessTokenFetcherImpl> token_fetcher_;
AuthorizationCompletedCallback callback_;
base::WeakPtrFactory<FileSystemSigninDialogDelegate> factory_{this};
};
} // namespace enterprise_connectors
#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_SIGNIN_DIALOG_DELEGATE_H_
......@@ -5757,7 +5757,10 @@ test("unit_tests") {
}
if (is_linux || is_chromeos || is_mac || is_win) {
sources += [ "../browser/enterprise/connectors/file_system/box_api_call_flow_unittests.cc" ]
sources += [
"../browser/enterprise/connectors/file_system/box_access_token_fetcher_unittests.cc",
"../browser/enterprise/connectors/file_system/box_api_call_flow_unittests.cc",
]
}
if (enable_plugins) {
......
......@@ -29,6 +29,7 @@ Refer to README.md for content description and update process.
<item id="blob_read" added_in_milestone="62" hash_code="112303907" type="0" deprecated="2019-08-09" content_hash_code="135449692" file_path=""/>
<item id="blob_reader" added_in_milestone="62" hash_code="5154306" type="0" deprecated="2018-06-14" content_hash_code="39702178" file_path=""/>
<item id="bluetooth_socket" added_in_milestone="65" hash_code="94099818" type="0" content_hash_code="30932349" os_list="linux,windows" file_path="device/bluetooth/bluetooth_socket_net.cc"/>
<item id="box_access_token_fetcher" added_in_milestone="89" hash_code="90263263" type="0" content_hash_code="120150044" os_list="linux,windows" file_path="chrome/browser/enterprise/connectors/file_system/box_access_token_fetcher.cc"/>
<item id="brandcode_config" added_in_milestone="62" hash_code="109679553" type="0" content_hash_code="128843792" os_list="linux,windows" file_path="chrome/browser/profile_resetter/brandcode_config_fetcher.cc"/>
<item id="browser_switcher_ieem_sitelist" added_in_milestone="72" hash_code="97159948" type="0" content_hash_code="129062966" os_list="linux,windows" file_path="chrome/browser/browser_switcher/browser_switcher_service.cc"/>
<item id="cablev2_websocket_from_authenticator" added_in_milestone="87" hash_code="28613769" type="0" content_hash_code="119863612" os_list="linux,windows" file_path="device/fido/cable/v2_authenticator.cc"/>
......
......@@ -161,6 +161,7 @@ hidden="true" so that these annotations don't show up in the document.
<traffic_annotation unique_id="kaleidoscope_service"/>
<traffic_annotation unique_id="webid"/>
<traffic_annotation unique_id="managed_configuration_loader"/>
<traffic_annotation unique_id="box_access_token_fetcher"/>
</sender>
</group>
<group name="Admin Features">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment