Commit ab4e11f3 authored by Vasilii Sukhanov's avatar Vasilii Sukhanov Committed by Commit Bot

Add basic leak detection classes and wire them in PasswordManager.

The leak check is supposed to happen on successful sign-in.

Bug: 986298
Change-Id: Id4745f70f7723aabeab5eb91ece92bad6f4b48bf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1727049
Commit-Queue: Vasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683121}
parent e5c49c04
...@@ -225,6 +225,7 @@ jumbo_static_library("browser") { ...@@ -225,6 +225,7 @@ jumbo_static_library("browser") {
"//components/keyed_service/core", "//components/keyed_service/core",
"//components/os_crypt", "//components/os_crypt",
"//components/password_manager/core/browser/form_parsing", "//components/password_manager/core/browser/form_parsing",
"//components/password_manager/core/browser/leak_detection:leak_detection_interface_headers",
"//components/password_manager/core/common", "//components/password_manager/core/common",
"//components/pref_registry", "//components/pref_registry",
"//components/prefs", "//components/prefs",
...@@ -255,6 +256,8 @@ jumbo_static_library("browser") { ...@@ -255,6 +256,8 @@ jumbo_static_library("browser") {
"hsts_query.h", "hsts_query.h",
"http_credentials_cleaner.cc", "http_credentials_cleaner.cc",
"http_credentials_cleaner.h", "http_credentials_cleaner.h",
"leak_detection_delegate.cc",
"leak_detection_delegate.h",
] ]
deps += [ deps += [
"//components/password_manager/core/browser/leak_detection:leak_detection", "//components/password_manager/core/browser/leak_detection:leak_detection",
...@@ -559,6 +562,7 @@ source_set("unit_tests") { ...@@ -559,6 +562,7 @@ source_set("unit_tests") {
"//components/password_manager/core/browser:proto", "//components/password_manager/core/browser:proto",
"//components/password_manager/core/browser/form_parsing:unit_tests", "//components/password_manager/core/browser/form_parsing:unit_tests",
"//components/password_manager/core/browser/form_parsing/fuzzer:unit_tests", "//components/password_manager/core/browser/form_parsing/fuzzer:unit_tests",
"//components/password_manager/core/browser/leak_detection:leak_detection_interface_headers",
"//components/password_manager/core/common", "//components/password_manager/core/common",
"//components/prefs:test_support", "//components/prefs:test_support",
"//components/security_state/core", "//components/security_state/core",
...@@ -589,6 +593,13 @@ source_set("unit_tests") { ...@@ -589,6 +593,13 @@ source_set("unit_tests") {
"//components/safe_browsing/common:safe_browsing_prefs", "//components/safe_browsing/common:safe_browsing_prefs",
] ]
} }
if (!is_ios) {
deps += [
"//components/password_manager/core/browser/leak_detection",
"//components/password_manager/core/browser/leak_detection:unit_tests",
]
}
} }
fuzzer_test("csv_reader_fuzzer") { fuzzer_test("csv_reader_fuzzer") {
......
...@@ -11,8 +11,51 @@ fuzzable_proto_library("proto") { ...@@ -11,8 +11,51 @@ fuzzable_proto_library("proto") {
] ]
} }
source_set("leak_detection_interface_headers") {
sources = [
"leak_detection_check.h",
"leak_detection_request_factory.h",
]
deps = [
"//base",
"//url",
]
}
jumbo_source_set("leak_detection") { jumbo_source_set("leak_detection") {
sources = [
"authenticated_leak_check.cc",
"authenticated_leak_check.h",
"leak_detection_check.h",
"leak_detection_request_factory.h",
"leak_detection_request_factory_impl.cc",
"leak_detection_request_factory_impl.h",
]
public_deps = [
":leak_detection_interface_headers",
]
deps = [ deps = [
":proto", ":proto",
"//base",
"//components/password_manager/core/common",
"//url",
]
}
jumbo_source_set("unit_tests") {
testonly = true
sources = [
"authenticated_leak_check_unittest.cc",
"leak_detection_request_factory_impl_unittest.cc",
]
deps = [
":leak_detection",
"//base/test:test_support",
"//components/password_manager/core/common",
"//testing/gmock",
"//testing/gtest",
] ]
} }
// Copyright 2019 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 "components/password_manager/core/browser/leak_detection/authenticated_leak_check.h"
namespace password_manager {
AuthenticatedLeakCheck::AuthenticatedLeakCheck() = default;
AuthenticatedLeakCheck::~AuthenticatedLeakCheck() = default;
void AuthenticatedLeakCheck::Start(const GURL& url,
base::StringPiece16 username,
base::StringPiece16 password) {}
} // namespace password_manager
// Copyright 2019 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_AUTHENTICATED_LEAK_CHECK_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_AUTHENTICATED_LEAK_CHECK_H_
#include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
namespace password_manager {
// Performs a leak-check for {username, password} for Chrome signed-in users.
class AuthenticatedLeakCheck : public LeakDetectionCheck {
public:
AuthenticatedLeakCheck();
~AuthenticatedLeakCheck() override;
void Start(const GURL& url,
base::StringPiece16 username,
base::StringPiece16 password) override;
};
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_AUTHENTICATED_LEAK_CHECK_H_
// Copyright 2019 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 "components/password_manager/core/browser/leak_detection/authenticated_leak_check.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace password_manager {
TEST(AuthenticatedLeakCheck, Create) {
AuthenticatedLeakCheck check;
}
} // namespace password_manager
// Copyright 2019 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_CHECK_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_CHECK_H_
#include "base/strings/string_piece_forward.h"
#include "url/gurl.h"
namespace password_manager {
// The base class for requests for checking if {username, password} pair was
// leaked in the internet.
class LeakDetectionCheck {
public:
LeakDetectionCheck() = default;
virtual ~LeakDetectionCheck() = default;
// Not copyable or movable
LeakDetectionCheck(const LeakDetectionCheck&) = delete;
LeakDetectionCheck& operator=(const LeakDetectionCheck&) = delete;
LeakDetectionCheck(LeakDetectionCheck&&) = delete;
LeakDetectionCheck& operator=(LeakDetectionCheck&&) = delete;
// Starts checking |username| and |password| pair asynchronously.
// |url| is used later for presentation in the UI but not for actual business
// logic.
virtual void Start(const GURL& url,
base::StringPiece16 username,
base::StringPiece16 password) = 0;
};
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_CHECK_H_
// Copyright 2019 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_FACTORY_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_FACTORY_H_
#include <memory>
namespace password_manager {
class LeakDetectionCheck;
// The interface for creating instances of requests for checking if
// {username, password} pair was leaked in the internet.
class LeakDetectionRequestFactory {
public:
LeakDetectionRequestFactory() = default;
virtual ~LeakDetectionRequestFactory() = default;
// Not copyable or movable
LeakDetectionRequestFactory(const LeakDetectionRequestFactory&) = delete;
LeakDetectionRequestFactory& operator=(const LeakDetectionRequestFactory&) =
delete;
LeakDetectionRequestFactory(LeakDetectionRequestFactory&&) = delete;
LeakDetectionRequestFactory& operator=(LeakDetectionRequestFactory&&) =
delete;
// The leak check is available only for signed-in users and if the feature is
// available.
virtual std::unique_ptr<LeakDetectionCheck> TryCreateLeakCheck() const = 0;
};
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_FACTORY_H_
// Copyright 2019 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 "components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h"
#include "components/password_manager/core/browser/leak_detection/authenticated_leak_check.h"
#include "components/password_manager/core/common/password_manager_features.h"
namespace password_manager {
LeakDetectionRequestFactoryImpl::LeakDetectionRequestFactoryImpl() = default;
LeakDetectionRequestFactoryImpl::~LeakDetectionRequestFactoryImpl() = default;
std::unique_ptr<LeakDetectionCheck>
LeakDetectionRequestFactoryImpl::TryCreateLeakCheck() const {
if (!base::FeatureList::IsEnabled(features::kLeakDetection))
return nullptr;
return std::make_unique<AuthenticatedLeakCheck>();
}
} // namespace password_manager
\ No newline at end of file
// Copyright 2019 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_FACTORY_IMPL_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_FACTORY_IMPL_H_
#include "base/macros.h"
#include "base/strings/string16.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_request_factory.h"
#include "url/gurl.h"
namespace password_manager {
// The class creates instances of requests for checking if {username, password}
// pair was leaked in the internet.
class LeakDetectionRequestFactoryImpl : public LeakDetectionRequestFactory {
public:
LeakDetectionRequestFactoryImpl();
~LeakDetectionRequestFactoryImpl() override;
std::unique_ptr<LeakDetectionCheck> TryCreateLeakCheck() const override;
};
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_FACTORY_IMPL_H_
// Copyright 2019 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 "components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h"
#include "base/test/scoped_feature_list.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace password_manager {
TEST(LeakDetectionRequestFactoryImpl, DisabledFeature) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(features::kLeakDetection);
LeakDetectionRequestFactoryImpl factory;
EXPECT_FALSE(factory.TryCreateLeakCheck());
}
} // namespace password_manager
// Copyright 2019 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 "components/password_manager/core/browser/leak_detection_delegate.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h"
namespace password_manager {
LeakDetectionDelegate::LeakDetectionDelegate()
: leak_factory_(std::make_unique<LeakDetectionRequestFactoryImpl>()) {}
LeakDetectionDelegate::~LeakDetectionDelegate() = default;
void LeakDetectionDelegate::StartLeakCheck(const autofill::PasswordForm& form) {
leak_check_ = leak_factory_->TryCreateLeakCheck();
if (leak_check_)
leak_check_->Start(form.origin, form.username_value, form.password_value);
}
} // namespace password_manager
// Copyright 2019 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_DELEGATE_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_DELEGATE_H_
#include <memory>
#include "components/password_manager/core/browser/leak_detection/leak_detection_request_factory.h"
namespace autofill {
struct PasswordForm;
} // namespace autofill
namespace password_manager {
class LeakDetectionCheck;
// The helper class that incapsulates the requests and their processing.
class LeakDetectionDelegate {
public:
LeakDetectionDelegate();
~LeakDetectionDelegate();
// Not copyable or movable
LeakDetectionDelegate(const LeakDetectionDelegate&) = delete;
LeakDetectionDelegate& operator=(const LeakDetectionDelegate&) = delete;
LeakDetectionDelegate(LeakDetectionDelegate&&) = delete;
LeakDetectionDelegate& operator=(LeakDetectionDelegate&&) = delete;
#if defined(UNIT_TEST)
void set_leak_factory(std::unique_ptr<LeakDetectionRequestFactory> factory) {
leak_factory_ = std::move(factory);
}
#endif // defined(UNIT_TEST)
void StartLeakCheck(const autofill::PasswordForm& form);
private:
// The factory that creates objects for performing a leak check up.
std::unique_ptr<LeakDetectionRequestFactory> leak_factory_;
// Current leak check-up being performed in the background.
std::unique_ptr<LeakDetectionCheck> leak_check_;
};
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_DELEGATE_H_
...@@ -1164,6 +1164,9 @@ void PasswordManager::OnLoginSuccessful() { ...@@ -1164,6 +1164,9 @@ void PasswordManager::OnLoginSuccessful() {
DCHECK(submitted_manager->GetSubmittedForm()); DCHECK(submitted_manager->GetSubmittedForm());
client_->GetStoreResultFilter()->ReportFormLoginSuccess(*submitted_manager); client_->GetStoreResultFilter()->ReportFormLoginSuccess(*submitted_manager);
#if !defined(OS_IOS)
leak_delegate_.StartLeakCheck(*submitted_manager->GetSubmittedForm());
#endif
auto submission_event = auto submission_event =
submitted_manager->GetSubmittedForm()->submission_event; submitted_manager->GetSubmittedForm()->submission_event;
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include "components/autofill/core/common/signatures_util.h" #include "components/autofill/core/common/signatures_util.h"
#include "components/password_manager/core/browser/form_parsing/password_field_prediction.h" #include "components/password_manager/core/browser/form_parsing/password_field_prediction.h"
#include "components/password_manager/core/browser/form_submission_observer.h" #include "components/password_manager/core/browser/form_submission_observer.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_request_factory.h"
#include "components/password_manager/core/browser/leak_detection_delegate.h"
#include "components/password_manager/core/browser/password_form_manager.h" #include "components/password_manager/core/browser/password_form_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_recorder.h" #include "components/password_manager/core/browser/password_manager_metrics_recorder.h"
...@@ -172,8 +174,13 @@ class PasswordManager : public FormSubmissionObserver { ...@@ -172,8 +174,13 @@ class PasswordManager : public FormSubmissionObserver {
PasswordFormManagerInterface* GetSubmittedManagerForTest() const { PasswordFormManagerInterface* GetSubmittedManagerForTest() const {
return GetSubmittedManager(); return GetSubmittedManager();
} }
#if !defined(OS_IOS)
void set_leak_factory(std::unique_ptr<LeakDetectionRequestFactory> factory) {
leak_delegate_.set_leak_factory(std::move(factory));
}
#endif // !defined(OS_IOS)
#endif #endif // defined(UNIT_TEST)
// Reports the priority of a PasswordGenerationRequirementsSpec for a // Reports the priority of a PasswordGenerationRequirementsSpec for a
// generated password. See // generated password. See
...@@ -403,6 +410,11 @@ class PasswordManager : public FormSubmissionObserver { ...@@ -403,6 +410,11 @@ class PasswordManager : public FormSubmissionObserver {
// CredentialManagerImpl takes care of it. // CredentialManagerImpl takes care of it.
bool store_password_called_ = false; bool store_password_called_ = false;
#if !defined(OS_IOS)
// Helper for making the requests on leak detection.
LeakDetectionDelegate leak_delegate_;
#endif // !defined(OS_IOS)
DISALLOW_COPY_AND_ASSIGN(PasswordManager); DISALLOW_COPY_AND_ASSIGN(PasswordManager);
}; };
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
...@@ -23,6 +24,8 @@ ...@@ -23,6 +24,8 @@
#include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h" #include "components/autofill/core/common/form_field_data.h"
#include "components/password_manager/core/browser/form_fetcher_impl.h" #include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_request_factory.h"
#include "components/password_manager/core/browser/mock_password_store.h" #include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/new_password_form_manager.h" #include "components/password_manager/core/browser/new_password_form_manager.h"
#include "components/password_manager/core/browser/password_autofill_manager.h" #include "components/password_manager/core/browser/password_autofill_manager.h"
...@@ -58,6 +61,7 @@ using base::Feature; ...@@ -58,6 +61,7 @@ using base::Feature;
using base::TestMockTimeTaskRunner; using base::TestMockTimeTaskRunner;
using testing::_; using testing::_;
using testing::AnyNumber; using testing::AnyNumber;
using testing::ByMove;
using testing::Invoke; using testing::Invoke;
using testing::IsNull; using testing::IsNull;
using testing::Mock; using testing::Mock;
...@@ -84,6 +88,17 @@ MATCHER_P(FormIgnoreDate, expected, "") { ...@@ -84,6 +88,17 @@ MATCHER_P(FormIgnoreDate, expected, "") {
return arg == expected_with_date; return arg == expected_with_date;
} }
class MockLeakDetectionCheck : public LeakDetectionCheck {
public:
MOCK_METHOD3(Start,
void(const GURL&, base::StringPiece16, base::StringPiece16));
};
class MockLeakDetectionRequestFactory : public LeakDetectionRequestFactory {
public:
MOCK_CONST_METHOD0(TryCreateLeakCheck, std::unique_ptr<LeakDetectionCheck>());
};
class MockStoreResultFilter : public StubCredentialsFilter { class MockStoreResultFilter : public StubCredentialsFilter {
public: public:
MOCK_CONST_METHOD1(ShouldSave, bool(const autofill::PasswordForm& form)); MOCK_CONST_METHOD1(ShouldSave, bool(const autofill::PasswordForm& form));
...@@ -3829,4 +3844,39 @@ TEST_F(PasswordManagerTest, FillingAndSavingFallbacksOnNonPasswordForm) { ...@@ -3829,4 +3844,39 @@ TEST_F(PasswordManagerTest, FillingAndSavingFallbacksOnNonPasswordForm) {
} }
} }
#if !defined(OS_IOS)
// Check that on successful login the credentials are checked for leak.
TEST_F(PasswordManagerTest, StartLeakDetection) {
auto mock_factory =
std::make_unique<testing::StrictMock<MockLeakDetectionRequestFactory>>();
MockLeakDetectionRequestFactory* weak_factory = mock_factory.get();
manager()->set_leak_factory(std::move(mock_factory));
const PasswordForm form = MakeSimpleForm();
std::vector<PasswordForm> observed = {form};
EXPECT_CALL(*store_, GetLogins)
.WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
OnPasswordFormSubmitted(form);
std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr)
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
auto check_instance = std::make_unique<MockLeakDetectionCheck>();
EXPECT_CALL(*check_instance,
Start(form.origin, base::StringPiece16(form.username_value),
base::StringPiece16(form.password_value)));
EXPECT_CALL(*weak_factory, TryCreateLeakCheck())
.WillOnce(Return(ByMove(std::move(check_instance))));
// Now the password manager waits for the navigation to complete.
observed.clear();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
#endif // !defined(OS_IOS)
} // namespace password_manager } // namespace password_manager
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