Skip to content

Commit d1396a8

Browse files
tanderson-googleChromium LUCI CQ
authored andcommitted
Use openAsync for KWallet in FreedesktopSecretKeyProvider
This CL switches FreedesktopSecretKeyProvider to use openAsync instead of open when using KWallet. This is to avoid timing out (the default DBus timeout is 25s) while KWallet prompts the user for a password. The sync backend will continue to use open instead of openAsync since it's going to be removed soon. R=thestig Fixed: 448853884 Change-Id: Iec000ce30f57fbcf757bb92e9ac2c0456ea38faf Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7056328 Reviewed-by: Lei Zhang <[email protected]> Commit-Queue: Thomas Anderson <[email protected]> Cr-Commit-Position: refs/heads/main@{#1532378}
1 parent 814b897 commit d1396a8

File tree

3 files changed

+155
-29
lines changed

3 files changed

+155
-29
lines changed

components/os_crypt/async/browser/freedesktop_secret_key_provider.cc

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "base/strings/string_util.h"
2525
#include "components/dbus/thread_linux/dbus_thread_linux.h"
2626
#include "components/dbus/utils/call_method.h"
27+
#include "components/dbus/utils/connect_to_signal.h"
2728
#include "components/dbus/utils/variant.h"
2829
#include "components/os_crypt/async/common/algorithm.mojom.h"
2930
#include "crypto/kdf.h"
@@ -171,8 +172,9 @@ class FreedesktopSecretKeyProvider::Prompter
171172
void StartPrompt() {
172173
auto* prompt_proxy = bus_->GetObjectProxy(
173174
FreedesktopSecretKeyProvider::kSecretServiceName, prompt_path_);
174-
prompt_proxy->ConnectToSignal(
175-
FreedesktopSecretKeyProvider::kSecretPromptInterface, "Completed",
175+
dbus_utils::ConnectToSignal(
176+
prompt_proxy, FreedesktopSecretKeyProvider::kSecretPromptInterface,
177+
"Completed",
176178
base::BindRepeating(&Prompter::OnPromptCompletedSignal, this),
177179
base::BindOnce(&Prompter::OnSignalConnected, this));
178180
dbus_utils::CallMethod<"s", "">(
@@ -197,23 +199,22 @@ class FreedesktopSecretKeyProvider::Prompter
197199
}
198200
}
199201

200-
void OnPromptCompletedSignal(dbus::Signal* signal) {
201-
dbus::MessageReader reader(signal);
202-
auto dismissed = dbus_utils::ReadValue<bool>(reader);
203-
auto variant = dbus_utils::ReadValue<dbus_utils::Variant>(reader);
204-
if (!dismissed.has_value() || !variant.has_value() ||
205-
reader.HasMoreData()) {
202+
void OnPromptCompletedSignal(
203+
dbus_utils::ConnectToSignalResult<bool, dbus_utils::Variant> result) {
204+
if (!result.has_value()) {
206205
LOG(ERROR) << "Failed to read Prompt.Completed signal args.";
207206
Finish(base::unexpected(ErrorDetail::kInvalidSignalFormat));
208207
return;
209208
}
210209

211-
if (dismissed.value()) {
210+
auto& [dismissed, variant] = result.value();
211+
212+
if (dismissed) {
212213
Finish(base::unexpected(ErrorDetail::kPromptDismissed));
213214
return;
214215
}
215216

216-
auto value = std::move(variant.value()).Take<T>();
217+
auto value = std::move(variant).Take<T>();
217218
if (!value) {
218219
LOG(ERROR) << "Failed to parse prompt result.";
219220
Finish(base::unexpected(ErrorDetail::kInvalidVariantFormat));
@@ -268,6 +269,8 @@ void FreedesktopSecretKeyProvider::GetKey(KeyCallback callback) {
268269

269270
// Reset state in case GetKey is called multiple times.
270271
kwallet_proxy_ = nullptr;
272+
kwallet_handle_ = kKWalletInvalidHandle;
273+
kwallet_transaction_id_ = kKWalletInvalidTransactionId;
271274
session_opened_ = false;
272275
session_proxy_ = nullptr;
273276
default_collection_proxy_ = nullptr;
@@ -580,23 +583,80 @@ void FreedesktopSecretKeyProvider::OnKWalletNetworkWallet(
580583
DbusErrorToErrorDetail(wallet_name.error()));
581584
return;
582585
}
583-
dbus_utils::CallMethod<"sxs", "i">(
584-
kwallet_proxy_, kKWalletInterface, kKWalletMethodOpen,
585-
base::BindOnce(&FreedesktopSecretKeyProvider::OnKWalletOpen,
586+
587+
dbus_utils::ConnectToSignal(
588+
kwallet_proxy_, kKWalletInterface, kKWalletSignalWalletAsyncOpened,
589+
base::BindRepeating(
590+
&FreedesktopSecretKeyProvider::OnKWalletWalletAsyncOpened,
591+
weak_ptr_factory_.GetWeakPtr()),
592+
base::BindOnce(&FreedesktopSecretKeyProvider::OnSignalConnected,
593+
weak_ptr_factory_.GetWeakPtr()));
594+
595+
// handleSession = true means KWallet will take care of keeping the wallet
596+
// open as long as the application is running.
597+
constexpr bool kHandleSession = true;
598+
dbus_utils::CallMethod<"sxsb", "i">(
599+
kwallet_proxy_, kKWalletInterface, kKWalletMethodOpenAsync,
600+
base::BindOnce(&FreedesktopSecretKeyProvider::OnKWalletOpenAsync,
586601
weak_ptr_factory_.GetWeakPtr()),
587-
std::get<0>(wallet_name.value()), 0, product_name_);
602+
std::get<0>(wallet_name.value()), 0, product_name_, kHandleSession);
603+
}
604+
605+
void FreedesktopSecretKeyProvider::OnKWalletOpenAsync(
606+
dbus_utils::CallMethodResultSig<"i"> t_id) {
607+
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
608+
if (!t_id.has_value()) {
609+
FinalizeFailure(InitStatus::kKWalletOpenFailed,
610+
DbusErrorToErrorDetail(t_id.error()));
611+
return;
612+
}
613+
614+
kwallet_transaction_id_ = std::get<0>(t_id.value());
615+
}
616+
617+
void FreedesktopSecretKeyProvider::OnSignalConnected(
618+
const std::string& interface_name,
619+
const std::string& signal_name,
620+
bool connected) {
621+
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
622+
if (!connected) {
623+
LOG(ERROR) << "Failed to connect to " << signal_name << " signal.";
624+
FinalizeFailure(InitStatus::kKWalletOpenFailed,
625+
ErrorDetail::kPromptFailedSignalConnection);
626+
}
588627
}
589628

590-
void FreedesktopSecretKeyProvider::OnKWalletOpen(
591-
dbus_utils::CallMethodResultSig<"i"> handle_reply) {
629+
void FreedesktopSecretKeyProvider::OnKWalletWalletAsyncOpened(
630+
dbus_utils::ConnectToSignalResult<int32_t, int32_t> result) {
592631
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
593-
if (!handle_reply.has_value()) {
632+
633+
if (kwallet_transaction_id_ == kKWalletInvalidTransactionId) {
634+
return;
635+
}
636+
637+
if (!result.has_value()) {
638+
LOG(ERROR) << "Failed to read walletAsyncOpened signal args.";
594639
FinalizeFailure(InitStatus::kKWalletOpenFailed,
595-
DbusErrorToErrorDetail(handle_reply.error()));
640+
ErrorDetail::kInvalidSignalFormat);
596641
return;
597642
}
598643

599-
kwallet_handle_ = std::get<0>(handle_reply.value());
644+
auto& [t_id, handle] = result.value();
645+
646+
if (t_id != kwallet_transaction_id_) {
647+
return;
648+
}
649+
650+
// Reset transaction ID to avoid processing the signal again.
651+
kwallet_transaction_id_ = kKWalletInvalidTransactionId;
652+
653+
OnKWalletOpen(handle);
654+
}
655+
656+
void FreedesktopSecretKeyProvider::OnKWalletOpen(int32_t handle) {
657+
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
658+
659+
kwallet_handle_ = handle;
600660
if (kwallet_handle_ == kKWalletInvalidHandle) {
601661
FinalizeFailure(InitStatus::kKWalletOpenFailed,
602662
ErrorDetail::kKWalletApiReturnedError);

components/os_crypt/async/browser/freedesktop_secret_key_provider.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "build/branding_buildflags.h"
2222
#include "components/dbus/utils/call_method.h"
2323
#include "components/dbus/utils/check_for_service_and_start.h"
24+
#include "components/dbus/utils/connect_to_signal.h"
2425
#include "components/dbus/utils/name_has_owner.h"
2526
#include "components/os_crypt/async/browser/key_provider.h"
2627
#include "dbus/bus.h"
@@ -130,14 +131,16 @@ class FreedesktopSecretKeyProvider : public KeyProvider {
130131
static constexpr char kKWalletInterface[] = "org.kde.KWallet";
131132
static constexpr char kKWalletMethodIsEnabled[] = "isEnabled";
132133
static constexpr char kKWalletMethodNetworkWallet[] = "networkWallet";
133-
static constexpr char kKWalletMethodOpen[] = "open";
134+
static constexpr char kKWalletMethodOpenAsync[] = "openAsync";
134135
static constexpr char kKWalletMethodReadPassword[] = "readPassword";
135136
static constexpr char kKWalletMethodClose[] = "close";
136137
static constexpr char kKWalletMethodHasFolder[] = "hasFolder";
137138
static constexpr char kKWalletMethodCreateFolder[] = "createFolder";
138139
static constexpr char kKWalletMethodHasEntry[] = "hasEntry";
139140
static constexpr char kKWalletMethodWritePassword[] = "writePassword";
140141

142+
static constexpr char kKWalletSignalWalletAsyncOpened[] = "walletAsyncOpened";
143+
141144
static constexpr char kDefaultAlias[] = "default";
142145

143146
// These constants are duplicated from the sync backend.
@@ -167,6 +170,7 @@ class FreedesktopSecretKeyProvider : public KeyProvider {
167170
static constexpr char kKWalletD6Path[] = "/modules/kwalletd6";
168171

169172
static constexpr int kKWalletInvalidHandle = -1;
173+
static constexpr int kKWalletInvalidTransactionId = -1;
170174

171175
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
172176
static constexpr char kKWalletFolder[] = "Chrome Keys";
@@ -196,7 +200,13 @@ class FreedesktopSecretKeyProvider : public KeyProvider {
196200
void OnKWalletServiceStarted(std::optional<bool> has_owner);
197201
void OnKWalletIsEnabled(dbus_utils::CallMethodResultSig<"b"> is_enabled);
198202
void OnKWalletNetworkWallet(dbus_utils::CallMethodResultSig<"s"> wallet_name);
199-
void OnKWalletOpen(dbus_utils::CallMethodResultSig<"i"> handle_reply);
203+
void OnKWalletOpenAsync(dbus_utils::CallMethodResultSig<"i"> t_id);
204+
void OnKWalletWalletAsyncOpened(
205+
dbus_utils::ConnectToSignalResult<int32_t, int32_t> result);
206+
void OnSignalConnected(const std::string& interface_name,
207+
const std::string& signal_name,
208+
bool connected);
209+
void OnKWalletOpen(int32_t handle);
200210
void OnKWalletHasFolder(dbus_utils::CallMethodResultSig<"b"> has_folder);
201211
void OnKWalletCreateFolder(dbus_utils::CallMethodResultSig<"b"> success);
202212
void OnKWalletHasEntry(dbus_utils::CallMethodResultSig<"b"> has_entry);
@@ -224,6 +234,7 @@ class FreedesktopSecretKeyProvider : public KeyProvider {
224234
// For KWallet password storage
225235
raw_ptr<dbus::ObjectProxy> kwallet_proxy_ = nullptr;
226236
int32_t kwallet_handle_ = kKWalletInvalidHandle;
237+
int32_t kwallet_transaction_id_ = kKWalletInvalidTransactionId;
227238

228239
const std::string password_store_;
229240
const std::string product_name_;

components/os_crypt/async/browser/freedesktop_secret_key_provider_unittest.cc

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ constexpr char kItemPromptPath[] =
5252
"/org/freedesktop/secrets/prompt/item_prompt";
5353
constexpr char kNetworkWallet[] = "kdewallet";
5454
constexpr int32_t kKWalletHandle = 42;
55+
constexpr int32_t kTransactionId = 123;
5556

5657
constexpr char kFakeSecret[] = "c3VwZXJfc2VjcmV0X2tleQ==";
5758

@@ -601,12 +602,29 @@ TEST(FreedesktopSecretKeyProviderTest, KWallet) {
601602
MatchArgs(), _))
602603
.WillOnce(RespondWith(std::string(kNetworkWallet)));
603604

604-
// open -> non-negative handle
605+
// ConnectToSignal walletAsyncOpened
606+
dbus::ObjectProxy::SignalCallback signal_callback;
607+
EXPECT_CALL(
608+
*mock_kwallet5_proxy,
609+
ConnectToSignal(
610+
FreedesktopSecretKeyProvider::kKWalletInterface,
611+
FreedesktopSecretKeyProvider::kKWalletSignalWalletAsyncOpened, _, _))
612+
.WillOnce([&](const std::string& interface_name,
613+
const std::string& signal_name,
614+
dbus::ObjectProxy::SignalCallback callback,
615+
dbus::ObjectProxy::OnConnectedCallback on_connected) {
616+
std::move(on_connected).Run(interface_name, signal_name, true);
617+
signal_callback = std::move(callback);
618+
});
619+
620+
// openAsync -> transaction ID
605621
EXPECT_CALL(*mock_kwallet5_proxy,
606622
Call(FreedesktopSecretKeyProvider::kKWalletInterface,
607-
FreedesktopSecretKeyProvider::kKWalletMethodOpen,
608-
MatchArgs(kNetworkWallet, int64_t(0), kProductName), _))
609-
.WillOnce(RespondWith(kKWalletHandle));
623+
FreedesktopSecretKeyProvider::kKWalletMethodOpenAsync,
624+
MatchArgs(kNetworkWallet, static_cast<int64_t>(0),
625+
kProductName, true),
626+
_))
627+
.WillOnce(RespondWith(kTransactionId));
610628

611629
// hasFolder -> true
612630
EXPECT_CALL(*mock_kwallet5_proxy,
@@ -657,6 +675,16 @@ TEST(FreedesktopSecretKeyProviderTest, KWallet) {
657675
key = std::move(returned_key.value());
658676
}));
659677

678+
// Simulate walletAsyncOpened signal
679+
ASSERT_TRUE(signal_callback);
680+
auto signal = dbus::Signal(
681+
FreedesktopSecretKeyProvider::kKWalletInterface,
682+
FreedesktopSecretKeyProvider::kKWalletSignalWalletAsyncOpened);
683+
dbus::MessageWriter writer(&signal);
684+
dbus_utils::WriteValue(writer, kTransactionId);
685+
dbus_utils::WriteValue(writer, kKWalletHandle);
686+
signal_callback.Run(&signal);
687+
660688
EXPECT_EQ(tag, "v11");
661689
EXPECT_TRUE(key.has_value());
662690
}
@@ -701,12 +729,29 @@ TEST(FreedesktopSecretKeyProviderTest, KWalletCreateFolderAndPassword) {
701729
MatchArgs(), _))
702730
.WillOnce(RespondWith(std::string(kNetworkWallet)));
703731

704-
// open -> non-negative handle
732+
// ConnectToSignal walletAsyncOpened
733+
dbus::ObjectProxy::SignalCallback signal_callback;
734+
EXPECT_CALL(
735+
*mock_kwallet6_proxy,
736+
ConnectToSignal(
737+
FreedesktopSecretKeyProvider::kKWalletInterface,
738+
FreedesktopSecretKeyProvider::kKWalletSignalWalletAsyncOpened, _, _))
739+
.WillOnce([&](const std::string& interface_name,
740+
const std::string& signal_name,
741+
dbus::ObjectProxy::SignalCallback callback,
742+
dbus::ObjectProxy::OnConnectedCallback on_connected) {
743+
std::move(on_connected).Run(interface_name, signal_name, true);
744+
signal_callback = std::move(callback);
745+
});
746+
747+
// openAsync -> transaction ID
705748
EXPECT_CALL(*mock_kwallet6_proxy,
706749
Call(FreedesktopSecretKeyProvider::kKWalletInterface,
707-
FreedesktopSecretKeyProvider::kKWalletMethodOpen,
708-
MatchArgs(kNetworkWallet, int64_t(0), kProductName), _))
709-
.WillOnce(RespondWith(kKWalletHandle));
750+
FreedesktopSecretKeyProvider::kKWalletMethodOpenAsync,
751+
MatchArgs(kNetworkWallet, static_cast<int64_t>(0),
752+
kProductName, true),
753+
_))
754+
.WillOnce(RespondWith(kTransactionId));
710755

711756
// hasFolder -> false
712757
EXPECT_CALL(*mock_kwallet6_proxy,
@@ -752,6 +797,16 @@ TEST(FreedesktopSecretKeyProviderTest, KWalletCreateFolderAndPassword) {
752797
key = std::move(returned_key.value());
753798
}));
754799

800+
// Simulate walletAsyncOpened signal
801+
ASSERT_TRUE(signal_callback);
802+
auto signal = dbus::Signal(
803+
FreedesktopSecretKeyProvider::kKWalletInterface,
804+
FreedesktopSecretKeyProvider::kKWalletSignalWalletAsyncOpened);
805+
dbus::MessageWriter writer(&signal);
806+
dbus_utils::WriteValue(writer, kTransactionId);
807+
dbus_utils::WriteValue(writer, kKWalletHandle);
808+
signal_callback.Run(&signal);
809+
755810
EXPECT_EQ(tag, "v11");
756811
EXPECT_TRUE(key.has_value());
757812
}

0 commit comments

Comments
 (0)