Commit 569a169a authored by Pavol Marko's avatar Pavol Marko Committed by Commit Bot

Properly propagate proxy auth details on sign-in screen (v2)

(Reland with WebviewProxyAuthLoginTest browsertext fix)
This CL fixes sign-in behind an authenticated proxy. Two actual changes
were necessary in this context:
- SigninPartitionManager: copy auth data from the system request
  context into new StoragePartitions
  This makes SigninPartitionManager::StartSigninSession async, which
  made small changes necessary in GaiaScreenHandler and
  EnrollmentScreenHandler
- SigninScreenHandler: Don't reload gaia immediately when auth details
  have been supplied. This was unnecessary (the URL Request will
  continue) and actually harmful, as now that we're using a new
  StoragePartition for each sign-in attempt, this discards auth data
  before we can copy them.

To support the browsertest, testserver.py gets an argument to redirect
CONNECT requests to localhost when proxying (in sign-in browsertests
without proxy, we use RuleBasedHostResolverProc::AddRule to achieve
this effect).

      unit_tests --gtest_filter=SigninPartitionManagerTest*
  Manual test:
   Setup:
     Setup an proxy server with Basic authentication
     Configure the device to use the proxy server.
     Make sure the user adding screen is shown.
   Test 1:
     Expect proxy auth dialog. Enter correct proxy auth data.
     Expect that sign-in screen is shown and sign-in works.
   Test 2:
     Expect proxy auth dialog. Enter incorrect proxy auth data.
     Expect that proxy-auth dialog is shown again.
   Test 3:
     Expect proxy auth dialog. Press Cancel.
     Expect that a network error dialog is shown.
     Press "try to sign in again".
     Expect proxy auth dialog. Enter correct proxy auth data.
     Expect that sign-in screen is shown and sign-in works.

Bug: 793524
Test: browser_tests --gtest_filter=WebviewProxyAuthLoginTest.* &&
Change-Id: I56dafa240ad3bb5902517688a5cb17e309f2982d
Reviewed-on: https://chromium-review.googlesource.com/850472Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Pavol Marko <pmarko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#527103}
parent eb2d85a1
......@@ -435,6 +435,7 @@ void ExistingUserController::Observe(
// just after the UI is closed but before the new credentials were stored
// in the profile. Therefore we have to give it some time to make sure it
// has been updated before we copy it.
// TODO(pmarko): Find a better way to do this, see https://crbug.com/796512.
VLOG(1) << "Authentication was entered manually, possibly for proxyauth.";
scoped_refptr<net::URLRequestContextGetter> browser_process_context_getter =
g_browser_process->system_request_context();
......
......@@ -6,17 +6,26 @@
#include "base/guid.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chromeos/chromeos_switches.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
#include "net/base/escape.h"
#include "net/http/http_auth_cache.h"
#include "net/http/http_network_session.h"
#include "net/http/http_transaction_factory.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
using content::BrowserThread;
namespace chromeos {
namespace login {
......@@ -46,18 +55,50 @@ void ClearStoragePartition(content::StoragePartition* storage_partition,
base::Time::Max(), std::move(partition_data_cleared));
}
net::URLRequestContextGetter* GetSystemURLRequestContextGetter() {
return g_browser_process->system_request_context();
}
// Transfers HttpAuthCache content from |main_url_request_context_getter| into
// |signin_url_request_context_getter|.
void PrepareSigninURLRequestContextOnIOThread(
net::URLRequestContextGetter* main_url_request_context_getter,
net::URLRequestContextGetter* signin_url_request_context_getter) {
// Transfer proxy auth data from the main URLRequestContext.
net::HttpAuthCache* main_http_auth_cache =
main_url_request_context_getter->GetURLRequestContext()
->http_transaction_factory()
->GetSession()
->http_auth_cache();
net::HttpAuthCache* signin_http_auth_cache =
signin_url_request_context_getter->GetURLRequestContext()
->http_transaction_factory()
->GetSession()
->http_auth_cache();
signin_http_auth_cache->UpdateAllFrom(*main_http_auth_cache);
}
void InvokeStartSigninSessionDoneCallback(
SigninPartitionManager::StartSigninSessionDoneCallback callback,
const std::string& partition_name) {
std::move(callback).Run(partition_name);
}
} // namespace
SigninPartitionManager::SigninPartitionManager(
content::BrowserContext* browser_context)
: browser_context_(browser_context),
clear_storage_partition_task_(
base::BindRepeating(&ClearStoragePartition)) {}
base::BindRepeating(&ClearStoragePartition)),
get_system_url_request_context_getter_task_(
base::BindRepeating(&GetSystemURLRequestContextGetter)) {}
SigninPartitionManager::~SigninPartitionManager() {}
void SigninPartitionManager::StartSigninSession(
const content::WebContents* embedder_web_contents) {
const content::WebContents* embedder_web_contents,
StartSigninSessionDoneCallback signin_session_started) {
// If we already were in a sign-in session, close it first.
// This clears stale data from the last-used StorageParittion.
CloseCurrentSigninSession(base::BindOnce(&base::DoNothing));
......@@ -74,6 +115,19 @@ void SigninPartitionManager::StartSigninSession(
current_storage_partition_ =
content::BrowserContext::GetStoragePartitionForSite(browser_context_,
guest_site, true);
base::OnceClosure invoke_callback = base::BindOnce(
&InvokeStartSigninSessionDoneCallback, std::move(signin_session_started),
current_storage_partition_name_);
BrowserThread::PostTaskAndReply(
BrowserThread::IO, FROM_HERE,
base::BindOnce(
&PrepareSigninURLRequestContextOnIOThread,
base::RetainedRef(get_system_url_request_context_getter_task_.Run()),
base::RetainedRef(
current_storage_partition_->GetURLRequestContext())),
std::move(invoke_callback));
}
void SigninPartitionManager::CloseCurrentSigninSession(
......@@ -97,6 +151,13 @@ void SigninPartitionManager::SetClearStoragePartitionTaskForTesting(
clear_storage_partition_task_ = clear_storage_partition_task;
}
void SigninPartitionManager::SetGetSystemURLRequestContextGetterTaskForTesting(
GetSystemURLRequestContextGetterTask
get_system_url_request_context_getter_task) {
get_system_url_request_context_getter_task_ =
get_system_url_request_context_getter_task;
}
const std::string& SigninPartitionManager::GetCurrentStoragePartitionName()
const {
DCHECK(IsInSigninSession());
......
......@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/keyed_service/core/keyed_service.h"
......@@ -19,6 +20,10 @@ class StoragePartition;
class WebContents;
} // namespace content
namespace net {
class URLRequestContextGetter;
}
namespace chromeos {
namespace login {
......@@ -30,6 +35,12 @@ class SigninPartitionManager : public KeyedService {
base::RepeatingCallback<void(content::StoragePartition* storage_partition,
base::OnceClosure data_cleared)>;
using GetSystemURLRequestContextGetterTask =
base::RepeatingCallback<net::URLRequestContextGetter*()>;
using StartSigninSessionDoneCallback =
base::OnceCallback<void(const std::string& partition_name)>;
explicit SigninPartitionManager(content::BrowserContext* browser_context);
~SigninPartitionManager() override;
......@@ -38,7 +49,11 @@ class SigninPartitionManager : public KeyedService {
// closed (and cleared).
// |embedder_web_contents| is the WebContents instance embedding the webview
// which will display the sign-in pages.
void StartSigninSession(const content::WebContents* embedder_web_contents);
// |signin_session_started| will be invoked with the partition name of the
// started signin session on completition.
void StartSigninSession(
const content::WebContents* embedder_web_contents,
StartSigninSessionDoneCallback signin_session_started);
// Closes the current StoragePartition. All cached data in the
// StoragePartition is cleared. |partition_data_cleared| will be called when
......@@ -66,6 +81,9 @@ class SigninPartitionManager : public KeyedService {
void SetClearStoragePartitionTaskForTesting(
ClearStoragePartitionTask clear_storage_partition_task);
void SetGetSystemURLRequestContextGetterTaskForTesting(
GetSystemURLRequestContextGetterTask
get_system_url_request_context_getter_task);
class Factory : public BrowserContextKeyedServiceFactory {
public:
......@@ -93,6 +111,8 @@ class SigninPartitionManager : public KeyedService {
content::BrowserContext* const browser_context_;
ClearStoragePartitionTask clear_storage_partition_task_;
GetSystemURLRequestContextGetterTask
get_system_url_request_context_getter_task_;
// GuestView StoragePartitions use the host of the embedder site's URL as the
// domain of their StoragePartition.
......
......@@ -12,13 +12,16 @@
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/web_contents_tester.h"
#include "net/cookies/cookie_store.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
......@@ -27,6 +30,39 @@ namespace login {
namespace {
constexpr char kEmbedderUrl[] = "http://www.whatever.com/";
void StorePartitionNameAndQuitLoop(base::RunLoop* loop,
std::string* out_partition_name,
const std::string& partition_name) {
*out_partition_name = partition_name;
loop->Quit();
}
void AddEntryToHttpAuthCache(
net::URLRequestContextGetter* url_request_context_getter) {
net::HttpAuthCache* http_auth_cache =
url_request_context_getter->GetURLRequestContext()
->http_transaction_factory()
->GetSession()
->http_auth_cache();
http_auth_cache->Add(GURL("http://whatever.com/"), "",
net::HttpAuth::AUTH_SCHEME_BASIC, "",
net::AuthCredentials(), "");
}
void IsEntryInHttpAuthCache(
net::URLRequestContextGetter* url_request_context_getter,
bool* out_entry_found) {
net::HttpAuthCache* http_auth_cache =
url_request_context_getter->GetURLRequestContext()
->http_transaction_factory()
->GetSession()
->http_auth_cache();
*out_entry_found =
http_auth_cache->Lookup(GURL("http://whatever.com/"), "",
net::HttpAuth::AUTH_SCHEME_BASIC) != nullptr;
}
} // namespace
class SigninPartitionManagerTest : public ChromeRenderViewHostTestHarness {
......@@ -37,6 +73,10 @@ class SigninPartitionManagerTest : public ChromeRenderViewHostTestHarness {
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
system_request_context_getter_ = new net::TestURLRequestContextGetter(
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::IO));
signin_browser_context_ = base::MakeUnique<TestingProfile>();
signin_ui_web_contents_ = base::WrapUnique<content::WebContents>(
......@@ -51,6 +91,10 @@ class SigninPartitionManagerTest : public ChromeRenderViewHostTestHarness {
GetSigninPartitionManager()->SetClearStoragePartitionTaskForTesting(
base::Bind(&SigninPartitionManagerTest::ClearStoragePartitionTask,
base::Unretained(this)));
GetSigninPartitionManager()
->SetGetSystemURLRequestContextGetterTaskForTesting(base::BindRepeating(
&SigninPartitionManagerTest::GetSystemURLRequestContextGetter,
base::Unretained(this)));
}
void TearDown() override {
......@@ -89,12 +133,29 @@ class SigninPartitionManagerTest : public ChromeRenderViewHostTestHarness {
pending_clear_tasks_.clear();
}
std::string RunStartSigninSesssion(content::WebContents* webcontents) {
std::string partition_name;
base::RunLoop loop;
GetSigninPartitionManager()->StartSigninSession(
webcontents,
base::BindOnce(&StorePartitionNameAndQuitLoop, &loop, &partition_name));
loop.Run();
return partition_name;
}
net::URLRequestContextGetter* GetSystemURLRequestContextGetter() {
return system_request_context_getter_.get();
}
private:
void ClearStoragePartitionTask(content::StoragePartition* partition,
base::OnceClosure clear_done_closure) {
pending_clear_tasks_.push_back({partition, std::move(clear_done_closure)});
}
scoped_refptr<net::TestURLRequestContextGetter>
system_request_context_getter_;
std::unique_ptr<TestingProfile> signin_browser_context_;
// Web contents of the sign-in UI, embedder of the signin-frame webview.
......@@ -108,20 +169,22 @@ class SigninPartitionManagerTest : public ChromeRenderViewHostTestHarness {
TEST_F(SigninPartitionManagerTest, TestSubsequentAttempts) {
// First sign-in attempt
GetSigninPartitionManager()->StartSigninSession(signin_ui_web_contents());
std::string signin_partition_name_1 =
GetSigninPartitionManager()->GetCurrentStoragePartitionName();
RunStartSigninSesssion(signin_ui_web_contents());
auto* signin_partition_1 =
GetSigninPartitionManager()->GetCurrentStoragePartition();
EXPECT_FALSE(signin_partition_name_1.empty());
EXPECT_EQ(signin_partition_name_1,
GetSigninPartitionManager()->GetCurrentStoragePartitionName());
// Second sign-in attempt
GetSigninPartitionManager()->StartSigninSession(signin_ui_web_contents());
std::string signin_partition_name_2 =
GetSigninPartitionManager()->GetCurrentStoragePartitionName();
RunStartSigninSesssion(signin_ui_web_contents());
auto* signin_partition_2 =
GetSigninPartitionManager()->GetCurrentStoragePartition();
EXPECT_FALSE(signin_partition_name_2.empty());
EXPECT_EQ(signin_partition_name_2,
GetSigninPartitionManager()->GetCurrentStoragePartitionName());
// Make sure that the StoragePartition has not been re-used.
EXPECT_NE(signin_partition_name_1, signin_partition_name_2);
......@@ -148,5 +211,32 @@ TEST_F(SigninPartitionManagerTest, TestSubsequentAttempts) {
EXPECT_TRUE(closure_called);
}
TEST_F(SigninPartitionManagerTest, HttpAuthCacheTransferred) {
base::RunLoop loop_prepare;
content::BrowserThread::PostTaskAndReply(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(AddEntryToHttpAuthCache,
base::RetainedRef(GetSystemURLRequestContextGetter())),
loop_prepare.QuitClosure());
loop_prepare.Run();
RunStartSigninSesssion(signin_ui_web_contents());
net::URLRequestContextGetter* signin_url_request_context_getter =
GetSigninPartitionManager()
->GetCurrentStoragePartition()
->GetURLRequestContext();
bool entry_found = false;
base::RunLoop loop_check;
content::BrowserThread::PostTaskAndReply(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(IsEntryInHttpAuthCache,
base::RetainedRef(signin_url_request_context_getter),
&entry_found),
loop_check.QuitClosure());
loop_check.Run();
EXPECT_TRUE(entry_found);
}
} // namespace login
} // namespace chromeos
......@@ -707,13 +707,16 @@ void EnrollmentScreenHandler::DoShow() {
login::SigninPartitionManager* signin_partition_manager =
login::SigninPartitionManager::Factory::GetForBrowserContext(
Profile::FromWebUI(web_ui()));
signin_partition_manager->StartSigninSession(web_ui()->GetWebContents());
signin_partition_manager->StartSigninSession(
web_ui()->GetWebContents(),
base::BindOnce(&EnrollmentScreenHandler::DoShowWithPartition,
weak_ptr_factory_.GetWeakPtr()));
}
// Then leave it running forever.
void EnrollmentScreenHandler::DoShowWithPartition(
const std::string& partition_name) {
base::DictionaryValue screen_data;
screen_data.SetString(
"webviewPartitionName",
signin_partition_manager->GetCurrentStoragePartitionName());
screen_data.SetString("webviewPartitionName", partition_name);
screen_data.SetString("gaiaUrl", GaiaUrls::GetInstance()->gaia_url().spec());
screen_data.SetString("clientId",
GaiaUrls::GetInstance()->oauth2_chrome_client_id());
......
......@@ -118,6 +118,9 @@ class EnrollmentScreenHandler
// Shows the screen.
void DoShow();
// Shows the screen.
void DoShowWithPartition(const std::string& partition_name);
// Returns true if current visible screen is the enrollment sign-in page.
bool IsOnEnrollmentScreen() const;
......
......@@ -300,31 +300,39 @@ void GaiaScreenHandler::DisableRestrictiveProxyCheckForTest() {
}
void GaiaScreenHandler::LoadGaia(const GaiaContext& context) {
// Start a new session with SigninPartitionManager, generating a unique
// StoragePartition.
login::SigninPartitionManager* signin_partition_manager =
login::SigninPartitionManager::Factory::GetForBrowserContext(
Profile::FromWebUI(web_ui()));
signin_partition_manager->StartSigninSession(
web_ui()->GetWebContents(),
base::BindOnce(&GaiaScreenHandler::LoadGaiaWithPartition,
weak_factory_.GetWeakPtr(), context));
}
void GaiaScreenHandler::LoadGaiaWithPartition(
const GaiaContext& context,
const std::string& partition_name) {
std::unique_ptr<std::string> version = std::make_unique<std::string>();
std::unique_ptr<bool> consent = std::make_unique<bool>();
base::OnceClosure get_version_and_consent =
base::BindOnce(&GetVersionAndConsent, base::Unretained(version.get()),
base::Unretained(consent.get()));
base::OnceClosure load_gaia = base::BindOnce(
&GaiaScreenHandler::LoadGaiaWithVersionAndConsent,
weak_factory_.GetWeakPtr(), context, base::Owned(version.release()),
base::Owned(consent.release()));
&GaiaScreenHandler::LoadGaiaWithPartitionAndVersionAndConsent,
weak_factory_.GetWeakPtr(), context, partition_name,
base::Owned(version.release()), base::Owned(consent.release()));
base::PostTaskWithTraitsAndReply(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
std::move(get_version_and_consent), std::move(load_gaia));
}
void GaiaScreenHandler::LoadGaiaWithVersionAndConsent(
void GaiaScreenHandler::LoadGaiaWithPartitionAndVersionAndConsent(
const GaiaContext& context,
const std::string& partition_name,
const std::string* platform_version,
const bool* collect_stats_consent) {
// Start a new session with SigninPartitionManager, generating a a unique
// StoragePartition.
login::SigninPartitionManager* signin_partition_manager =
login::SigninPartitionManager::Factory::GetForBrowserContext(
Profile::FromWebUI(web_ui()));
signin_partition_manager->StartSigninSession(web_ui()->GetWebContents());
base::DictionaryValue params;
params.SetBoolean("forceReload", context.force_reload);
......@@ -400,8 +408,8 @@ void GaiaScreenHandler::LoadGaiaWithVersionAndConsent(
// sending device statistics.
if (*collect_stats_consent)
params.SetString("lsbReleaseBoard", base::SysInfo::GetLsbReleaseBoard());
params.SetString("webviewPartitionName",
signin_partition_manager->GetCurrentStoragePartitionName());
params.SetString("webviewPartitionName", partition_name);
frame_state_ = FRAME_STATE_LOADING;
CallJS("loadAuthExtension", params);
......
......@@ -64,9 +64,16 @@ class GaiaScreenHandler : public BaseScreenHandler,
// Callback that loads GAIA after version and stat consent information has
// been retrieved.
void LoadGaiaWithVersionAndConsent(const GaiaContext& context,
const std::string* platform_version,
const bool* collect_stats_consent);
void LoadGaiaWithPartition(const GaiaContext& context,
const std::string& partition_name);
// Callback that loads GAIA after version and stat consent information has
// been retrieved.
void LoadGaiaWithPartitionAndVersionAndConsent(
const GaiaContext& context,
const std::string& partition_name,
const std::string* platform_version,
const bool* collect_stats_consent);
// Sends request to reload Gaia. If |force_reload| is true, request
// will be sent in any case, otherwise it will be sent only when Gaia is
......
......@@ -685,7 +685,8 @@ void SigninScreenHandler::UpdateStateInternal(NetworkError::ErrorReason reason,
// Skip "update" notification about OFFLINE state from
// NetworkStateInformer if previous notification already was
// delayed.
if ((state == NetworkStateInformer::OFFLINE || has_pending_auth_ui_) &&
if ((state == NetworkStateInformer::OFFLINE ||
network_state_ignored_until_proxy_auth_) &&
!force_update && !update_state_closure_.IsCancelled()) {
return;
}
......@@ -693,7 +694,7 @@ void SigninScreenHandler::UpdateStateInternal(NetworkError::ErrorReason reason,
update_state_closure_.Cancel();
if ((state == NetworkStateInformer::OFFLINE && !force_update) ||
has_pending_auth_ui_) {
network_state_ignored_until_proxy_auth_) {
update_state_closure_.Reset(
base::Bind(&SigninScreenHandler::UpdateStateInternal,
weak_factory_.GetWeakPtr(),
......@@ -789,7 +790,6 @@ void SigninScreenHandler::UpdateStateInternal(NetworkError::ErrorReason reason,
if (is_gaia_loading_timeout) {
LOG(WARNING) << "Retry frame load due to loading timeout.";
LOG(ERROR) << "UpdateStateInternal reload 4";
reload_gaia.ScheduleCall();
}
......@@ -1082,20 +1082,33 @@ void SigninScreenHandler::Observe(int type,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_AUTH_NEEDED: {
has_pending_auth_ui_ = true;
network_state_ignored_until_proxy_auth_ = true;
break;
}
case chrome::NOTIFICATION_AUTH_SUPPLIED:
has_pending_auth_ui_ = false;
// Reload auth extension as proxy credentials are supplied.
if (!IsSigninScreenHiddenByError() && ui_state_ == UI_STATE_GAIA_SIGNIN)
ReloadGaia(true);
update_state_closure_.Cancel();
case chrome::NOTIFICATION_AUTH_SUPPLIED: {
if (IsGaiaHiddenByError()) {
// Start listening to network state notifications immediately, hoping
// that the network will switch to ONLINE soon.
update_state_closure_.Cancel();
ReenableNetworkStateUpdatesAfterProxyAuth();
} else {
// Gaia is not hidden behind an error yet. Discard last cached network
// state notification and wait for |kOfflineTimeoutSec| before
// considering network update notifications again (hoping the network
// will become ONLINE by then).
update_state_closure_.Cancel();
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(
&SigninScreenHandler::ReenableNetworkStateUpdatesAfterProxyAuth,
weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(kOfflineTimeoutSec));
}
break;
}
case chrome::NOTIFICATION_AUTH_CANCELLED: {
// Don't reload auth extension if proxy auth dialog was cancelled.
has_pending_auth_ui_ = false;
update_state_closure_.Cancel();
ReenableNetworkStateUpdatesAfterProxyAuth();
break;
}
default:
......@@ -1103,6 +1116,10 @@ void SigninScreenHandler::Observe(int type,
}
}
void SigninScreenHandler::ReenableNetworkStateUpdatesAfterProxyAuth() {
network_state_ignored_until_proxy_auth_ = false;
}
void SigninScreenHandler::SuspendDone(const base::TimeDelta& sleep_duration) {
for (user_manager::User* user :
user_manager::UserManager::Get()->GetUnlockUsers()) {
......
......@@ -483,6 +483,10 @@ class SigninScreenHandler
// Called when the cros property controlling allowed input methods changes.
void OnAllowedInputMethodsChanged();
// After proxy auth information has been supplied, this function re-enables
// responding to network state notifications.
void ReenableNetworkStateUpdatesAfterProxyAuth();
// Current UI state of the signin screen.
UIState ui_state_ = UI_STATE_UNKNOWN;
......@@ -522,10 +526,10 @@ class SigninScreenHandler
std::unique_ptr<CrosSettings::ObserverSubscription>
allowed_input_methods_subscription_;
// Whether there is an auth UI pending. This flag is set on receiving
// NOTIFICATION_AUTH_NEEDED and reset on either NOTIFICATION_AUTH_SUPPLIED or
// NOTIFICATION_AUTH_CANCELLED.
bool has_pending_auth_ui_ = false;
// Whether we're currently ignoring network state updates because a proxy auth
// UI pending (or we're waiting for a grace period after the proxy auth UI is
// finished for the network to switch into the ONLINE state).
bool network_state_ignored_until_proxy_auth_ = false;
// Used for pending GAIA reloads.
NetworkError::ErrorReason gaia_reload_reason_ =
......
......@@ -508,6 +508,12 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const {
arguments->Set("no-anonymous-ftp-user", std::make_unique<base::Value>());
}
if (redirect_connect_to_localhost_) {
DCHECK_EQ(TYPE_BASIC_AUTH_PROXY, type_);
arguments->Set("redirect-connect-to-localhost",
std::make_unique<base::Value>());
}
if (UsingSSL(type_)) {
// Check the certificate arguments of the HTTPS server.
base::FilePath certificate_path(certificates_dir_);
......
......@@ -370,6 +370,11 @@ class BaseTestServer {
no_anonymous_ftp_user_ = no_anonymous_ftp_user;
}
// Redirect proxied CONNECT requests to localhost.
void set_redirect_connect_to_localhost(bool redirect_connect_to_localhost) {
redirect_connect_to_localhost_ = redirect_connect_to_localhost;
}
// Marks the root certificate of an HTTPS test server as trusted for
// the duration of tests.
bool LoadTestRootCert() const WARN_UNUSED_RESULT;
......@@ -454,6 +459,9 @@ class BaseTestServer {
// Disable creation of anonymous FTP user?
bool no_anonymous_ftp_user_ = false;
// Redirect proxied CONNECT requests to localhost?
bool redirect_connect_to_localhost_ = false;
std::unique_ptr<ScopedPortException> allowed_port_;
DISALLOW_COPY_AND_ASSIGN(BaseTestServer);
......
......@@ -1765,6 +1765,7 @@ class BasicAuthProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""
_AUTH_CREDENTIAL = 'Basic Zm9vOmJhcg==' # foo:bar
redirect_connect_to_localhost = False;
def parse_request(self):
"""Overrides parse_request to check credential."""
......@@ -1850,6 +1851,9 @@ class BasicAuthProxyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self.send_response(400)
self.end_headers()
if BasicAuthProxyRequestHandler.redirect_connect_to_localhost:
host = "127.0.0.1"
try:
sock = socket.create_connection((host, port))
self.send_response(200, 'Connection established')
......@@ -2108,6 +2112,8 @@ class ServerRunner(testserver_base.TestServerRunner):
print 'Echo UDP server started on port %d...' % server.server_port
server_data['port'] = server.server_port
elif self.options.server_type == SERVER_BASIC_AUTH_PROXY:
BasicAuthProxyRequestHandler.redirect_connect_to_localhost = \
self.options.redirect_connect_to_localhost
server = HTTPServer((host, port), BasicAuthProxyRequestHandler)
print 'BasicAuthProxy server started on port %d...' % server.server_port
server_data['port'] = server.server_port
......@@ -2323,6 +2329,12 @@ class ServerRunner(testserver_base.TestServerRunner):
action='store_true')
self.option_parser.add_option('--token-binding-params', action='append',
default=[], type='int')
self.option_parser.add_option('--redirect-connect-to-localhost',
dest='redirect_connect_to_localhost',
default=False, action='store_true',
help='If set, the Proxy server will connect '
'to localhost instead of the requested URL '
'on CONNECT requests')
if __name__ == '__main__':
......
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