system-proxy: Request credentials from browser
When a ProxyConnectJob fails with "proxy auth required", the job will
ask for credentials from the ServerProxy object which owns it.
If the credentials are in the ServerProxy auth cache, the request will
be resolved with those credentials.
If not, the request will be forwarded to the parent process which will
send a dbus call to the browser to notify that it needs credentials for
a specific protection space (proxy_url, scheme, realm).
The browser will then send credentials along with the protection space
via dbus, with empty username and password if the user hasn't entered
them yet.
The dbus response is then forwarded to the ProxyConnectJob which made
the original request.
BUG=chromium:1042642
TEST=unittest
Change-Id: I1f5d43971d18df98aeb7c0b25642ceb29c761915
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2245699
Reviewed-by: Pavol Marko <pmarko@chromium.org>
Tested-by: Andreea-Elena Costinas <acostinas@google.com>
Commit-Queue: Andreea-Elena Costinas <acostinas@google.com>
diff --git a/system-proxy/server_proxy.cc b/system-proxy/server_proxy.cc
index ea93796..6662c92 100644
--- a/system-proxy/server_proxy.cc
+++ b/system-proxy/server_proxy.cc
@@ -97,8 +97,45 @@
const std::string& scheme,
const std::string& realm,
OnAuthAcquiredCallback callback) {
- // TODO(acostinas): Request the credentials from the main process.
- std::move(callback).Run(std::string());
+ worker::ProtectionSpace protection_space;
+ protection_space.set_origin(proxy_url);
+ protection_space.set_realm(realm);
+ protection_space.set_scheme(scheme);
+
+ std::string auth_key = protection_space.SerializeAsString();
+ // Check the local cache.
+ auto it = auth_cache_.find(auth_key);
+ if (it != auth_cache_.end()) {
+ std::move(callback).Run(it->second);
+ return;
+ }
+
+ // Request the credentials from the main process.
+ worker::AuthRequiredRequest auth_request;
+ *auth_request.mutable_protection_space() = protection_space;
+
+ worker::WorkerRequest request;
+ *request.mutable_auth_required_request() = auth_request;
+
+ if (!WriteProtobuf(GetStdoutPipe(), request)) {
+ LOG(ERROR) << "Failed to send authentication required request";
+ std::move(callback).Run(/* credentials= */ std::string());
+ return;
+ }
+ pending_auth_required_requests_[auth_key].push_back(std::move(callback));
+}
+
+void ServerProxy::AuthCredentialsProvided(
+ const std::string& auth_credentials_key, const std::string& credentials) {
+ auto it = pending_auth_required_requests_.find(auth_credentials_key);
+ if (it == pending_auth_required_requests_.end()) {
+ LOG(WARNING) << "No pending requests found for credentials";
+ return;
+ }
+ for (auto& auth_acquired_callback : it->second) {
+ std::move(auth_acquired_callback).Run(credentials);
+ }
+ pending_auth_required_requests_.erase(auth_credentials_key);
}
void ServerProxy::HandleStdinReadable() {
@@ -109,10 +146,23 @@
}
if (config.has_credentials()) {
+ std::string credentials;
const std::string username = UrlEncode(config.credentials().username());
const std::string password = UrlEncode(config.credentials().password());
- system_credentials_ = base::JoinString({username.c_str(), password.c_str()},
- kCredentialsColonSeparator);
+ credentials = base::JoinString({username.c_str(), password.c_str()},
+ kCredentialsColonSeparator);
+ if (config.credentials().has_protection_space()) {
+ std::string auth_key =
+ config.credentials().protection_space().SerializeAsString();
+ if (!username.empty() && !password.empty()) {
+ auth_cache_[auth_key] = credentials;
+ AuthCredentialsProvided(auth_key, credentials);
+ } else {
+ AuthCredentialsProvided(auth_key, std::string());
+ }
+ } else {
+ system_credentials_ = credentials;
+ }
}
if (config.has_listening_address()) {