| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/policy/remote_commands/crd_host_delegate.h" |
| |
| #include <string> |
| |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/ash/policy/remote_commands/crd_logging.h" |
| #include "chrome/browser/ash/policy/remote_commands/crd_remote_command_utils.h" |
| #include "chrome/browser/ash/policy/remote_commands/device_command_start_crd_session_job.h" |
| #include "remoting/host/chromeos/remote_support_host_ash.h" |
| #include "remoting/host/chromeos/remoting_service.h" |
| #include "remoting/host/mojom/remote_support.mojom.h" |
| #include "remoting/protocol/errors.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace policy { |
| |
| using AccessCodeCallback = DeviceCommandStartCrdSessionJob::AccessCodeCallback; |
| using ErrorCallback = DeviceCommandStartCrdSessionJob::ErrorCallback; |
| using SessionEndCallback = DeviceCommandStartCrdSessionJob::SessionEndCallback; |
| |
| namespace { |
| |
| // Default implementation of the RemotingService, which will contact the real |
| // remoting service. |
| class DefaultRemotingService : public CrdHostDelegate::RemotingServiceProxy { |
| public: |
| DefaultRemotingService() = default; |
| DefaultRemotingService(const DefaultRemotingService&) = delete; |
| DefaultRemotingService& operator=(const DefaultRemotingService&) = delete; |
| ~DefaultRemotingService() override = default; |
| |
| // CrdHostDelegate::RemotingService implementation: |
| |
| void StartSession(remoting::mojom::SupportSessionParamsPtr params, |
| const remoting::ChromeOsEnterpriseParams& enterprise_params, |
| StartSessionCallback callback) override { |
| return remoting::RemotingService::Get().GetSupportHost().StartSession( |
| std::move(params), enterprise_params, std::move(callback)); |
| } |
| }; |
| |
| } // namespace |
| |
| class CrdHostDelegate::CrdHostSession |
| : public remoting::mojom::SupportHostObserver { |
| public: |
| CrdHostSession(const SessionParameters& parameters, |
| AccessCodeCallback success_callback, |
| ErrorCallback error_callback, |
| SessionEndCallback session_finished_callback) |
| : parameters_(parameters), |
| success_callback_(std::move(success_callback)), |
| error_callback_(std::move(error_callback)), |
| session_finished_callback_(std::move(session_finished_callback)) {} |
| CrdHostSession(const CrdHostSession&) = delete; |
| CrdHostSession& operator=(const CrdHostSession&) = delete; |
| ~CrdHostSession() override = default; |
| |
| void Start(CrdHostDelegate::RemotingServiceProxy& remoting_service) { |
| CRD_DVLOG(3) << "Starting CRD session with parameters { " |
| "user_name '" |
| << parameters_.user_name << "', terminate_upon_input " |
| << parameters_.terminate_upon_input |
| << ", show_confirmation_dialog " |
| << parameters_.show_confirmation_dialog |
| << ", curtain_local_user_session " |
| << parameters_.curtain_local_user_session << "}"; |
| |
| remoting_service.StartSession( |
| GetSessionParameters(), GetEnterpriseParameters(), |
| base::BindOnce(&CrdHostSession::OnStartSupportSessionResponse, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| // remoting::mojom::SupportHostObserver implementation: |
| void OnHostStateStarting() override { CRD_DVLOG(3) << __FUNCTION__; } |
| void OnHostStateRequestedAccessCode() override { |
| CRD_DVLOG(3) << __FUNCTION__; |
| } |
| void OnHostStateReceivedAccessCode(const std::string& access_code, |
| base::TimeDelta lifetime) override { |
| CRD_DVLOG(3) << __FUNCTION__; |
| |
| ReportSuccess(access_code); |
| } |
| void OnHostStateConnecting() override { CRD_DVLOG(3) << __FUNCTION__; } |
| void OnHostStateConnected(const std::string& remote_username) override { |
| CRD_DVLOG(3) << __FUNCTION__; |
| session_connected_time_ = base::Time::Now(); |
| } |
| void OnHostStateDisconnected( |
| const absl::optional<std::string>& disconnect_reason) override { |
| // We always want to log this event, as it could help customers debug why |
| // their CRD connection is failing/disconnecting. |
| LOG(WARNING) << "CRD session disconnected with reason: " |
| << disconnect_reason.value_or("<none>"); |
| if (session_connected_time_.has_value()) { |
| ReportSessionTermination(base::Time::Now() - |
| session_connected_time_.value()); |
| } |
| ReportError(ResultCode::FAILURE_CRD_HOST_ERROR, "host disconnected"); |
| } |
| void OnNatPolicyChanged( |
| remoting::mojom::NatPolicyStatePtr nat_policy_state) override { |
| CRD_DVLOG(3) << __FUNCTION__; |
| } |
| void OnHostStateError(int64_t error_code) override { |
| CRD_DVLOG(3) << __FUNCTION__ << " with error code: " << error_code; |
| |
| if (error_code == remoting::protocol::ErrorCode::DISALLOWED_BY_POLICY) { |
| ReportError(ResultCode::FAILURE_DISABLED_BY_POLICY, |
| "enterprise remote support disabled"); |
| return; |
| } |
| |
| ReportError(ResultCode::FAILURE_CRD_HOST_ERROR, "host state error"); |
| } |
| void OnPolicyError() override { |
| CRD_DVLOG(3) << __FUNCTION__; |
| |
| ReportError(ResultCode::FAILURE_CRD_HOST_ERROR, "policy error"); |
| } |
| void OnInvalidDomainError() override { |
| CRD_DVLOG(3) << __FUNCTION__; |
| |
| ReportError(ResultCode::FAILURE_CRD_HOST_ERROR, "invalid domain error"); |
| } |
| |
| private: |
| void OnStartSupportSessionResponse( |
| remoting::mojom::StartSupportSessionResponsePtr response) { |
| if (response->is_support_session_error()) { |
| ReportError(ResultCode::FAILURE_CRD_HOST_ERROR, ""); |
| return; |
| } |
| |
| observer_.Bind(std::move(response->get_observer())); |
| } |
| |
| remoting::mojom::SupportSessionParamsPtr GetSessionParameters() const { |
| auto result = remoting::mojom::SupportSessionParams::New(); |
| result->user_name = parameters_.user_name; |
| // Note the oauth token must be prefixed with 'oauth2:', or it will be |
| // rejected by the CRD host. |
| result->oauth_access_token = "oauth2:" + parameters_.oauth_token; |
| |
| // TODO(joedow): Set the |authorized_helper| field once it is provided by |
| // the admin console and available in |parameters_|. |
| |
| return result; |
| } |
| |
| remoting::ChromeOsEnterpriseParams GetEnterpriseParameters() const { |
| return remoting::ChromeOsEnterpriseParams{ |
| .suppress_user_dialogs = !parameters_.show_confirmation_dialog, |
| .suppress_notifications = !parameters_.show_confirmation_dialog, |
| .terminate_upon_input = parameters_.terminate_upon_input, |
| .curtain_local_user_session = parameters_.curtain_local_user_session}; |
| } |
| |
| void ReportSuccess(const std::string& access_code) { |
| if (success_callback_) { |
| std::move(success_callback_).Run(access_code); |
| |
| success_callback_.Reset(); |
| error_callback_.Reset(); |
| } |
| } |
| |
| void ReportError(ResultCode error_code, const std::string& error_message) { |
| if (error_callback_) { |
| std::move(error_callback_).Run(error_code, error_message); |
| |
| success_callback_.Reset(); |
| error_callback_.Reset(); |
| } |
| } |
| |
| void ReportSessionTermination(base::TimeDelta session_duration) { |
| if (session_finished_callback_) { |
| std::move(session_finished_callback_).Run(session_duration); |
| |
| session_finished_callback_.Reset(); |
| } |
| } |
| |
| SessionParameters parameters_; |
| AccessCodeCallback success_callback_; |
| ErrorCallback error_callback_; |
| SessionEndCallback session_finished_callback_; |
| absl::optional<base::Time> session_connected_time_; |
| |
| mojo::Receiver<remoting::mojom::SupportHostObserver> observer_{this}; |
| base::WeakPtrFactory<CrdHostSession> weak_factory_{this}; |
| }; |
| |
| CrdHostDelegate::CrdHostDelegate() |
| : CrdHostDelegate(std::make_unique<DefaultRemotingService>()) {} |
| |
| CrdHostDelegate::CrdHostDelegate( |
| std::unique_ptr<RemotingServiceProxy> remoting_service) |
| : remoting_service_(std::move(remoting_service)) {} |
| |
| CrdHostDelegate::~CrdHostDelegate() = default; |
| |
| bool CrdHostDelegate::HasActiveSession() const { |
| return active_session_ != nullptr; |
| } |
| |
| void CrdHostDelegate::TerminateSession(base::OnceClosure callback) { |
| CRD_DVLOG(3) << "Terminating CRD session"; |
| active_session_ = nullptr; |
| std::move(callback).Run(); |
| } |
| |
| void CrdHostDelegate::StartCrdHostAndGetCode( |
| const SessionParameters& parameters, |
| AccessCodeCallback success_callback, |
| ErrorCallback error_callback, |
| SessionEndCallback session_finished_callback) { |
| DCHECK(!active_session_); |
| active_session_ = std::make_unique<CrdHostSession>( |
| parameters, std::move(success_callback), std::move(error_callback), |
| std::move(session_finished_callback)); |
| |
| active_session_->Start(*remoting_service_); |
| } |
| |
| } // namespace policy |