Skip to content

Commit

Permalink
Add processing logic to WellKnownChangePasswordNavigationThrottle
Browse files Browse the repository at this point in the history
Bug: 927473
Change-Id: Ifbca9e259a11f6f8a83c10393dd69c4be66bd17f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2228613
Commit-Queue: Jonathan Mengedoht <mengedoht@google.com>
Reviewed-by: Vasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#786752}
  • Loading branch information
Jonathan Mengedoht authored and Commit Bot committed Jul 9, 2020
1 parent c2f9e3b commit b284f1a
Show file tree
Hide file tree
Showing 6 changed files with 390 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,67 @@
#include "chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.h"

#include "base/logging.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_user_data.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "url/gurl.h"

namespace {

using chrome::kWellKnownChangePasswordPath;
using chrome::kWellKnownNotExistingResourcePath;
using content::NavigationHandle;
using content::NavigationThrottle;
using content::WebContents;

// This path should return 404. This enables us to check whether
// we can trust the server's response code.
// https://wicg.github.io/change-password-url/response-code-reliability.html#iana
constexpr char kNotExistingResourcePath[] =
".well-known/"
"resource-that-should-not-exist-whose-status-code-should-not-be-200";
// Used to scope the posted navigation task to the lifetime of |web_contents|.
class WebContentsLifetimeHelper
: public content::WebContentsUserData<WebContentsLifetimeHelper> {
public:
explicit WebContentsLifetimeHelper(WebContents* web_contents)
: web_contents_(web_contents) {}

base::WeakPtr<WebContentsLifetimeHelper> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}

void NavigateTo(const content::OpenURLParams& url_params) {
web_contents_->OpenURL(url_params);
}

private:
friend class content::WebContentsUserData<WebContentsLifetimeHelper>;

WebContents* const web_contents_;
base::WeakPtrFactory<WebContentsLifetimeHelper> weak_factory_{this};

WEB_CONTENTS_USER_DATA_KEY_DECL();
};

WEB_CONTENTS_USER_DATA_KEY_IMPL(WebContentsLifetimeHelper)

bool IsWellKnownChangePasswordUrl(const GURL& url) {
return url.is_valid() && url.has_path() &&
(url.PathForRequest() == "/.well-known/change-password" ||
url.PathForRequest() == "/.well-known/change-password/");
if (!url.is_valid() || !url.has_path())
return false;
base::StringPiece path = url.PathForRequestPiece();
// remove trailing slash if there
if (path.ends_with("/"))
path = path.substr(0, path.size() - 1);
return path == kWellKnownChangePasswordPath;
}

GURL CreateNonExistingResourceURL(const GURL& url) {
GURL::Replacements replacement;
replacement.SetPathStr(kNotExistingResourcePath);
replacement.SetPathStr(kWellKnownNotExistingResourcePath);
return url.GetOrigin().ReplaceComponents(replacement);
}

Expand Down Expand Up @@ -75,15 +104,16 @@ WellKnownChangePasswordNavigationThrottle::WillStartRequest() {

NavigationThrottle::ThrottleCheckResult
WellKnownChangePasswordNavigationThrottle::WillFailRequest() {
url_loader_.reset();
return NavigationThrottle::PROCEED;
}

NavigationThrottle::ThrottleCheckResult
WellKnownChangePasswordNavigationThrottle::WillProcessResponse() {
change_password_response_code_ =
navigation_handle()->GetResponseHeaders()->response_code();
// TODO(crbug.com/927473) handle processing
return NavigationThrottle::PROCEED;
return BothRequestsFinished() ? ContinueProcessing()
: NavigationThrottle::DEFER;
}

const char* WellKnownChangePasswordNavigationThrottle::GetNameForLogging() {
Expand Down Expand Up @@ -124,11 +154,9 @@ void WellKnownChangePasswordNavigationThrottle::FetchNonExistingResource(
setting: "This feature cannot be disabled."
policy_exception_justification: "Essential for navigation."
})");
auto url_loader_factory =
content::BrowserContext::GetDefaultStoragePartition(
Profile::FromBrowserContext(
handle->GetWebContents()->GetBrowserContext()))
->GetURLLoaderFactoryForBrowserProcess();
auto url_loader_factory = content::BrowserContext::GetDefaultStoragePartition(
handle->GetWebContents()->GetBrowserContext())
->GetURLLoaderFactoryForBrowserProcess();
url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
traffic_annotation);
// Binding the callback to |this| is safe, because the navigationthrottle
Expand All @@ -144,6 +172,58 @@ void WellKnownChangePasswordNavigationThrottle::FetchNonExistingResource(
void WellKnownChangePasswordNavigationThrottle::
FetchNonExistingResourceCallback(
scoped_refptr<net::HttpResponseHeaders> headers) {
if (!headers) {
non_existing_resource_response_code_ = -1;
return;
}
non_existing_resource_response_code_ = headers->response_code();
// TODO(crbug.com/927473) handle processing
if (BothRequestsFinished()) {
ThrottleAction action = ContinueProcessing();
if (action == NavigationThrottle::PROCEED) {
Resume();
}
}
}

NavigationThrottle::ThrottleAction
WellKnownChangePasswordNavigationThrottle::ContinueProcessing() {
DCHECK(BothRequestsFinished());
if (SupportsChangePasswordUrl()) {
return NavigationThrottle::PROCEED;
} else {
// TODO(crbug.com/1086141): Integrate Service that provides URL overrides
Redirect(navigation_handle()->GetURL().GetOrigin());
return NavigationThrottle::CANCEL;
}
}

void WellKnownChangePasswordNavigationThrottle::Redirect(const GURL& url) {
content::OpenURLParams params =
content::OpenURLParams::FromNavigationHandle(navigation_handle());
params.url = url;
params.transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;

WebContents* web_contents = navigation_handle()->GetWebContents();
if (!web_contents)
return;

WebContentsLifetimeHelper::CreateForWebContents(web_contents);
WebContentsLifetimeHelper* helper =
WebContentsLifetimeHelper::FromWebContents(web_contents);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&WebContentsLifetimeHelper::NavigateTo,
helper->GetWeakPtr(), std::move(params)));
}

bool WellKnownChangePasswordNavigationThrottle::BothRequestsFinished() const {
return non_existing_resource_response_code_ != 0 &&
change_password_response_code_ != 0;
}

bool WellKnownChangePasswordNavigationThrottle::SupportsChangePasswordUrl()
const {
DCHECK(BothRequestsFinished());
return 200 <= change_password_response_code_ &&
change_password_response_code_ < 300 &&
non_existing_resource_response_code_ == net::HTTP_NOT_FOUND;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "content/public/browser/navigation_throttle.h"

class GURL;
namespace content {
class NavigationHandle;
} // namespace content
Expand Down Expand Up @@ -52,6 +53,15 @@ class WellKnownChangePasswordNavigationThrottle
// Callback for the request to the "not exist" path.
void FetchNonExistingResourceCallback(
scoped_refptr<net::HttpResponseHeaders> headers);
// Function is called when both requests are finished. Decides to continue or
// redirect to homepage.
ThrottleAction ContinueProcessing();
// Redirects to a given URL in the same tab.
void Redirect(const GURL& url);
// Checks if both requests are finished.
bool BothRequestsFinished() const;
// Checks the status codes and returns if change password is supported.
bool SupportsChangePasswordUrl() const;

int non_existing_resource_response_code_ = 0;
int change_password_response_code_ = 0;
Expand Down
Loading

0 comments on commit b284f1a

Please sign in to comment.