Commit 18671723 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[Passwords] Support x-origin redirects in WellKnown Throttle

This change modifies the WellKnownChangePasswordNavigationThrottle to
use the URL used in the beginning of the navigation for the fallback
logic in case the server does not support .well-known/change-password
URLs.

So far it has been using `navigation_handle()->GetURL()`, which could
change in the presence of server-side redirects and thus could point
to a different origin, for which the fallback logic would be wrong.

Fixed: 1130519
Change-Id: I8177f7a8f794de91d2cf81d92aab11179280f73c
Bug: 1130519
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2421512Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#809306}
parent 0fcaf722
...@@ -109,6 +109,7 @@ WellKnownChangePasswordNavigationThrottle::MaybeCreateThrottleFor( ...@@ -109,6 +109,7 @@ WellKnownChangePasswordNavigationThrottle::MaybeCreateThrottleFor(
WellKnownChangePasswordNavigationThrottle:: WellKnownChangePasswordNavigationThrottle::
WellKnownChangePasswordNavigationThrottle(NavigationHandle* handle) WellKnownChangePasswordNavigationThrottle(NavigationHandle* handle)
: NavigationThrottle(handle), : NavigationThrottle(handle),
request_url_(handle->GetURL()),
source_id_( source_id_(
ukm::GetSourceIdForWebContentsDocument(handle->GetWebContents())) { ukm::GetSourceIdForWebContentsDocument(handle->GetWebContents())) {
if (base::FeatureList::IsEnabled( if (base::FeatureList::IsEnabled(
...@@ -117,7 +118,7 @@ WellKnownChangePasswordNavigationThrottle:: ...@@ -117,7 +118,7 @@ WellKnownChangePasswordNavigationThrottle::
AffiliationServiceFactory::GetForProfile(Profile::FromBrowserContext( AffiliationServiceFactory::GetForProfile(Profile::FromBrowserContext(
handle->GetWebContents()->GetBrowserContext())); handle->GetWebContents()->GetBrowserContext()));
well_known_change_password_state_.PrefetchChangePasswordURLs( well_known_change_password_state_.PrefetchChangePasswordURLs(
affiliation_service_, {navigation_handle()->GetURL()}); affiliation_service_, {request_url_});
} else { } else {
change_password_url_service_ = change_password_url_service_ =
ChangePasswordUrlServiceFactory::GetForBrowserContext( ChangePasswordUrlServiceFactory::GetForBrowserContext(
...@@ -146,7 +147,7 @@ WellKnownChangePasswordNavigationThrottle::WillStartRequest() { ...@@ -146,7 +147,7 @@ WellKnownChangePasswordNavigationThrottle::WillStartRequest() {
net::IsolationInfo::RedirectMode::kUpdateNothing, net::IsolationInfo::RedirectMode::kUpdateNothing,
navigation_handle()->GetIsolationInfo().network_isolation_key()); navigation_handle()->GetIsolationInfo().network_isolation_key());
well_known_change_password_state_.FetchNonExistingResource( well_known_change_password_state_.FetchNonExistingResource(
url_loader_factory.get(), navigation_handle()->GetURL(), url_loader_factory.get(), request_url_,
navigation_handle()->GetInitiatorOrigin(), std::move(trusted_params)); navigation_handle()->GetInitiatorOrigin(), std::move(trusted_params));
return NavigationThrottle::PROCEED; return NavigationThrottle::PROCEED;
} }
...@@ -183,20 +184,20 @@ void WellKnownChangePasswordNavigationThrottle::OnProcessingFinished( ...@@ -183,20 +184,20 @@ void WellKnownChangePasswordNavigationThrottle::OnProcessingFinished(
Resume(); Resume();
return; return;
} }
GURL url = navigation_handle()->GetURL();
GURL redirect_url; GURL redirect_url;
if (base::FeatureList::IsEnabled( if (base::FeatureList::IsEnabled(
password_manager::features::kChangePasswordAffiliationInfo)) { password_manager::features::kChangePasswordAffiliationInfo)) {
redirect_url = affiliation_service_->GetChangePasswordURL(url); redirect_url = affiliation_service_->GetChangePasswordURL(request_url_);
} else { } else {
redirect_url = change_password_url_service_->GetChangePasswordUrl(url); redirect_url =
change_password_url_service_->GetChangePasswordUrl(request_url_);
} }
if (redirect_url.is_valid()) { if (redirect_url.is_valid()) {
RecordMetric(WellKnownChangePasswordResult::kFallbackToOverrideUrl); RecordMetric(WellKnownChangePasswordResult::kFallbackToOverrideUrl);
Redirect(redirect_url); Redirect(redirect_url);
} else { } else {
RecordMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl); RecordMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl);
Redirect(url.GetOrigin()); Redirect(request_url_.GetOrigin());
} }
CancelDeferredNavigation(NavigationThrottle::CANCEL); CancelDeferredNavigation(NavigationThrottle::CANCEL);
} }
......
...@@ -57,6 +57,10 @@ class WellKnownChangePasswordNavigationThrottle ...@@ -57,6 +57,10 @@ class WellKnownChangePasswordNavigationThrottle
// Records the given UKM metric. // Records the given UKM metric.
void RecordMetric(password_manager::WellKnownChangePasswordResult result); void RecordMetric(password_manager::WellKnownChangePasswordResult result);
// Stores `navigation_handle()->GetURL()` if the first navigation was to
// .well-known/change-password. It is later used to derive the URL for the
// non-existing resource, and to provide fallback logic.
const GURL request_url_;
password_manager::WellKnownChangePasswordState password_manager::WellKnownChangePasswordState
well_known_change_password_state_{this}; well_known_change_password_state_{this};
ukm::SourceId source_id_ = ukm::kInvalidSourceId; ukm::SourceId source_id_ = ukm::kInvalidSourceId;
......
...@@ -57,6 +57,7 @@ using net::test_server::HttpResponse; ...@@ -57,6 +57,7 @@ using net::test_server::HttpResponse;
using password_manager::kWellKnownChangePasswordPath; using password_manager::kWellKnownChangePasswordPath;
using password_manager::kWellKnownNotExistingResourcePath; using password_manager::kWellKnownNotExistingResourcePath;
using password_manager::WellKnownChangePasswordResult; using password_manager::WellKnownChangePasswordResult;
using testing::Return;
constexpr char kMockChangePasswordPath[] = "/change-password-override"; constexpr char kMockChangePasswordPath[] = "/change-password-override";
...@@ -77,24 +78,11 @@ struct ResponseDelayParams { ...@@ -77,24 +78,11 @@ struct ResponseDelayParams {
} // namespace } // namespace
class TestChangePasswordUrlService class MockChangePasswordUrlService
: public password_manager::ChangePasswordUrlService { : public password_manager::ChangePasswordUrlService {
public: public:
void PrefetchURLs() override {} void PrefetchURLs() override {}
MOCK_METHOD(GURL, GetChangePasswordUrl, (const GURL&), (override));
GURL GetChangePasswordUrl(const GURL& url) override {
if (override_available_) {
GURL::Replacements replacement;
replacement.SetPathStr(kMockChangePasswordPath);
return url.ReplaceComponents(replacement);
}
return GURL();
}
void SetOverrideAvailable(bool available) { override_available_ = available; }
private:
bool override_available_ = false;
}; };
class ChangePasswordNavigationThrottleBrowserTestBase class ChangePasswordNavigationThrottleBrowserTestBase
...@@ -111,6 +99,7 @@ class ChangePasswordNavigationThrottleBrowserTestBase ...@@ -111,6 +99,7 @@ class ChangePasswordNavigationThrottleBrowserTestBase
} }
void Initialize() { void Initialize() {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server_->InitializeAndListen()); ASSERT_TRUE(test_server_->InitializeAndListen());
test_server_->StartAcceptingConnections(); test_server_->StartAcceptingConnections();
test_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); test_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
...@@ -211,7 +200,7 @@ class WellKnownChangePasswordNavigationThrottleBrowserTest ...@@ -211,7 +200,7 @@ class WellKnownChangePasswordNavigationThrottleBrowserTest
void SetUpOnMainThread() override; void SetUpOnMainThread() override;
void TestNavigationThrottleForLocalhost(const std::string& expected_path); void TestNavigationThrottleForLocalhost(const std::string& expected_path);
TestChangePasswordUrlService* url_service_ = nullptr; MockChangePasswordUrlService* url_service_ = nullptr;
private: private:
base::test::ScopedFeatureList feature_list_; base::test::ScopedFeatureList feature_list_;
...@@ -224,7 +213,8 @@ void WellKnownChangePasswordNavigationThrottleBrowserTest::SetUpOnMainThread() { ...@@ -224,7 +213,8 @@ void WellKnownChangePasswordNavigationThrottleBrowserTest::SetUpOnMainThread() {
->SetTestingSubclassFactoryAndUse( ->SetTestingSubclassFactoryAndUse(
browser()->profile(), browser()->profile(),
base::BindRepeating([](content::BrowserContext*) { base::BindRepeating([](content::BrowserContext*) {
return std::make_unique<TestChangePasswordUrlService>(); return std::make_unique<
testing::StrictMock<MockChangePasswordUrlService>>();
})); }));
} }
...@@ -336,11 +326,14 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, ...@@ -336,11 +326,14 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest,
} }
} }
IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, IN_PROC_BROWSER_TEST_P(
SupportForChangePassword_WithRedirectToNotFoundPage) { WellKnownChangePasswordNavigationThrottleBrowserTest,
SupportForChangePassword_WithXOriginRedirectToNotFoundPage) {
GURL change_password_url =
test_server_->GetURL("example.com", "/change-password");
path_response_map_[kWellKnownChangePasswordPath] = { path_response_map_[kWellKnownChangePasswordPath] = {
net::HTTP_PERMANENT_REDIRECT, net::HTTP_PERMANENT_REDIRECT,
{std::make_pair("Location", "/change-password")}, {std::make_pair("Location", change_password_url.spec())},
response_delays().change_password_delay}; response_delays().change_password_delay};
path_response_map_[kWellKnownNotExistingResourcePath] = { path_response_map_[kWellKnownNotExistingResourcePath] = {
net::HTTP_PERMANENT_REDIRECT, net::HTTP_PERMANENT_REDIRECT,
...@@ -349,7 +342,8 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, ...@@ -349,7 +342,8 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest,
path_response_map_["/change-password"] = {net::HTTP_OK, {}, 0}; path_response_map_["/change-password"] = {net::HTTP_OK, {}, 0};
path_response_map_["/not-found"] = {net::HTTP_NOT_FOUND, {}, 0}; path_response_map_["/not-found"] = {net::HTTP_NOT_FOUND, {}, 0};
TestNavigationThrottleForLocalhost(/*expected_path=*/"/change-password"); TestNavigationThrottle(test_server_->GetURL(kWellKnownChangePasswordPath),
change_password_url);
if (page_transition() & ui::PAGE_TRANSITION_FROM_API) { if (page_transition() & ui::PAGE_TRANSITION_FROM_API) {
ExpectUkmMetric( ExpectUkmMetric(
WellKnownChangePasswordResult::kUsedWellKnownChangePassword); WellKnownChangePasswordResult::kUsedWellKnownChangePassword);
...@@ -367,6 +361,9 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, ...@@ -367,6 +361,9 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest,
net::HTTP_NOT_FOUND, {}, response_delays().not_exist_delay}; net::HTTP_NOT_FOUND, {}, response_delays().not_exist_delay};
if (page_transition() & ui::PAGE_TRANSITION_FROM_API) { if (page_transition() & ui::PAGE_TRANSITION_FROM_API) {
EXPECT_CALL(*url_service_, GetChangePasswordUrl(test_server_->GetURL(
kWellKnownChangePasswordPath)))
.WillOnce(Return(GURL()));
TestNavigationThrottleForLocalhost(/*expected_path=*/"/"); TestNavigationThrottleForLocalhost(/*expected_path=*/"/");
ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl); ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl);
} else { } else {
...@@ -379,13 +376,15 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, ...@@ -379,13 +376,15 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest,
IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest,
NoSupportForChangePassword_WithUrlOverride) { NoSupportForChangePassword_WithUrlOverride) {
url_service_->SetOverrideAvailable(true);
path_response_map_[kWellKnownChangePasswordPath] = { path_response_map_[kWellKnownChangePasswordPath] = {
net::HTTP_NOT_FOUND, {}, response_delays().change_password_delay}; net::HTTP_NOT_FOUND, {}, response_delays().change_password_delay};
path_response_map_[kWellKnownNotExistingResourcePath] = { path_response_map_[kWellKnownNotExistingResourcePath] = {
net::HTTP_NOT_FOUND, {}, response_delays().not_exist_delay}; net::HTTP_NOT_FOUND, {}, response_delays().not_exist_delay};
if (page_transition() & ui::PAGE_TRANSITION_FROM_API) { if (page_transition() & ui::PAGE_TRANSITION_FROM_API) {
EXPECT_CALL(*url_service_, GetChangePasswordUrl(test_server_->GetURL(
kWellKnownChangePasswordPath)))
.WillOnce(Return(test_server_->GetURL(kMockChangePasswordPath)));
TestNavigationThrottleForLocalhost( TestNavigationThrottleForLocalhost(
/*expected_path=*/kMockChangePasswordPath); /*expected_path=*/kMockChangePasswordPath);
ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOverrideUrl); ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOverrideUrl);
...@@ -406,6 +405,9 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, ...@@ -406,6 +405,9 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest,
net::HTTP_OK, {}, response_delays().not_exist_delay}; net::HTTP_OK, {}, response_delays().not_exist_delay};
if (page_transition() & ui::PAGE_TRANSITION_FROM_API) { if (page_transition() & ui::PAGE_TRANSITION_FROM_API) {
EXPECT_CALL(*url_service_, GetChangePasswordUrl(test_server_->GetURL(
kWellKnownChangePasswordPath)))
.WillOnce(Return(GURL()));
TestNavigationThrottleForLocalhost(/*expected_path=*/"/"); TestNavigationThrottleForLocalhost(/*expected_path=*/"/");
ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl); ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl);
} else { } else {
...@@ -416,23 +418,31 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, ...@@ -416,23 +418,31 @@ IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest,
} }
} }
IN_PROC_BROWSER_TEST_P(WellKnownChangePasswordNavigationThrottleBrowserTest, IN_PROC_BROWSER_TEST_P(
NoSupportForChangePassword_WithRedirectToNotFoundPage) { WellKnownChangePasswordNavigationThrottleBrowserTest,
NoSupportForChangePassword_WithXOriginRedirectToNotFoundPage) {
// Test a cross-origin redirect to a 404 page. Ensure that we try to obtain
// the ChangePasswordUrl for the original origin.
GURL not_found_url = test_server_->GetURL("example.com", "/not-found");
path_response_map_[kWellKnownChangePasswordPath] = { path_response_map_[kWellKnownChangePasswordPath] = {
net::HTTP_PERMANENT_REDIRECT, net::HTTP_PERMANENT_REDIRECT,
{std::make_pair("Location", "/not-found")}, {std::make_pair("Location", not_found_url.spec())},
response_delays().change_password_delay}; response_delays().change_password_delay};
path_response_map_[kWellKnownNotExistingResourcePath] = { path_response_map_[kWellKnownNotExistingResourcePath] = {
net::HTTP_PERMANENT_REDIRECT, net::HTTP_PERMANENT_REDIRECT,
{std::make_pair("Location", "/not-found")}, {std::make_pair("Location", not_found_url.spec())},
response_delays().not_exist_delay}; response_delays().not_exist_delay};
path_response_map_["/not-found"] = {net::HTTP_NOT_FOUND, {}, 0}; path_response_map_["/not-found"] = {net::HTTP_NOT_FOUND, {}, 0};
if (page_transition() & ui::PAGE_TRANSITION_FROM_API) { if (page_transition() & ui::PAGE_TRANSITION_FROM_API) {
EXPECT_CALL(*url_service_, GetChangePasswordUrl(test_server_->GetURL(
kWellKnownChangePasswordPath)))
.WillOnce(Return(GURL()));
TestNavigationThrottleForLocalhost(/*expected_path=*/"/"); TestNavigationThrottleForLocalhost(/*expected_path=*/"/");
ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl); ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl);
} else { } else {
TestNavigationThrottleForLocalhost(/*expected_path=*/"/not-found"); TestNavigationThrottle(test_server_->GetURL(kWellKnownChangePasswordPath),
not_found_url);
EXPECT_TRUE( EXPECT_TRUE(
test_recorder()->GetEntriesByName(UkmBuilder::kEntryName).empty()); test_recorder()->GetEntriesByName(UkmBuilder::kEntryName).empty());
} }
...@@ -506,7 +516,6 @@ class AffiliationChangePasswordNavigationThrottleBrowserTest ...@@ -506,7 +516,6 @@ class AffiliationChangePasswordNavigationThrottleBrowserTest
void AffiliationChangePasswordNavigationThrottleBrowserTest:: void AffiliationChangePasswordNavigationThrottleBrowserTest::
SetUpOnMainThread() { SetUpOnMainThread() {
Initialize(); Initialize();
host_resolver()->AddRule("*", "127.0.0.1");
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory = scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
......
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