| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/host/setup/corp_host_starter.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/sequence_checker.h" |
| #include "base/strings/string_util.h" |
| #include "remoting/base/corp_service_client.h" |
| #include "remoting/base/http_status.h" |
| #include "remoting/base/internal_headers.h" |
| #include "remoting/host/host_config.h" |
| #include "remoting/host/setup/buildflags.h" |
| #include "remoting/host/setup/host_starter.h" |
| #include "remoting/host/setup/host_starter_base.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| |
| namespace remoting { |
| |
| namespace { |
| |
| // A helper class which provisions a corp machine for Chrome Remote Desktop. |
| class CorpHostStarter : public HostStarterBase { |
| public: |
| CorpHostStarter( |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| std::unique_ptr<net::ClientCertStore> client_cert_store); |
| |
| CorpHostStarter(const CorpHostStarter&) = delete; |
| CorpHostStarter& operator=(const CorpHostStarter&) = delete; |
| |
| ~CorpHostStarter() override; |
| |
| // HostStarterBase implementation. |
| void RegisterNewHost(std::optional<std::string> access_token) override; |
| void RemoveOldHostFromDirectory(base::OnceClosure on_host_removed) override; |
| void ApplyConfigValues(base::Value::Dict& config) override; |
| void ReportError(const std::string& error_message, |
| base::OnceClosure on_error_reported) override; |
| |
| // CorpServiceClient callback. |
| void OnProvisionCorpMachineResponse( |
| const HttpStatus& status, |
| std::unique_ptr<internal::ProvisionCorpMachineResponse> response); |
| |
| private: |
| std::unique_ptr<CorpServiceClient> corp_service_client_; |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| |
| base::WeakPtrFactory<CorpHostStarter> weak_ptr_factory_{this}; |
| }; |
| |
| CorpHostStarter::CorpHostStarter( |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| std::unique_ptr<net::ClientCertStore> client_cert_store) |
| : HostStarterBase(url_loader_factory), |
| corp_service_client_( |
| std::make_unique<CorpServiceClient>(url_loader_factory, |
| std::move(client_cert_store))) {} |
| |
| CorpHostStarter::~CorpHostStarter() = default; |
| |
| void CorpHostStarter::RegisterNewHost(std::optional<std::string> access_token) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| // We don't expect |access_token| to be populated for this flow. |
| DCHECK(!access_token.has_value()); |
| |
| corp_service_client_->ProvisionCorpMachine( |
| params().username, params().name, key_pair().GetPublicKey(), |
| existing_host_id(), |
| base::BindOnce(&CorpHostStarter::OnProvisionCorpMachineResponse, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void CorpHostStarter::OnProvisionCorpMachineResponse( |
| const HttpStatus& status, |
| std::unique_ptr<internal::ProvisionCorpMachineResponse> response) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| if (!status.ok()) { |
| HandleHttpStatusError(status); |
| return; |
| } |
| |
| OnNewHostRegistered( |
| base::ToLowerASCII(internal::GetHostId(*response)), |
| base::ToLowerASCII(internal::GetOwnerEmail(*response)), |
| base::ToLowerASCII(internal::GetServiceAccount(*response)), |
| internal::GetAuthorizationCode(*response)); |
| } |
| |
| void CorpHostStarter::RemoveOldHostFromDirectory( |
| base::OnceClosure on_host_removed) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| // This workflow removes the existing host as part of the provisioning service |
| // call so we don't need to make an additional service request here. |
| std::move(on_host_removed).Run(); |
| } |
| |
| void CorpHostStarter::ApplyConfigValues(base::Value::Dict& config) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| config.Set(kRequireSessionAuthorizationPath, true); |
| config.Set(kHostTypeHintPath, kCorpHostTypeHint); |
| } |
| |
| void CorpHostStarter::ReportError(const std::string& message, |
| base::OnceClosure on_error_reported) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| const std::string& host_id = params().id; |
| LOG(ERROR) << "\n Reporting provisioning error for host id `" << host_id |
| << "`:\n " << message; |
| corp_service_client_->ReportProvisioningError( |
| host_id, message, |
| base::BindOnce( |
| [](base::OnceClosure on_error_reported, const HttpStatus& status, |
| std::unique_ptr<Empty>) { |
| if (!status.ok()) { |
| LOG(ERROR) << "Failed to report provisioning error: " |
| << static_cast<int>(status.error_code()); |
| } |
| std::move(on_error_reported).Run(); |
| }, |
| std::move(on_error_reported))); |
| } |
| |
| } // namespace |
| |
| std::unique_ptr<HostStarter> ProvisionCorpMachine( |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| std::unique_ptr<net::ClientCertStore> client_cert_store) { |
| return std::make_unique<CorpHostStarter>(url_loader_factory, |
| std::move(client_cert_store)); |
| } |
| |
| } // namespace remoting |