blob: e06d5f4258448149f3fd66240caa3344132f7d7c [file] [log] [blame]
// Copyright 2018 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 CHROME_BROWSER_CHROMEOS_POLICY_AUTO_ENROLLMENT_CLIENT_IMPL_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_AUTO_ENROLLMENT_CLIENT_IMPL_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "services/network/public/cpp/network_connection_tracker.h"
#include "third_party/protobuf/src/google/protobuf/repeated_field.h"
class PrefRegistrySimple;
class PrefService;
namespace private_membership {
namespace rlwe {
class PrivateMembershipRlweClient;
class RlwePlaintextId;
} // namespace rlwe
} // namespace private_membership
namespace enterprise_management {
class DeviceManagementResponse;
}
namespace policy {
// Construct the PSM (private set membership) identifier. See
// go/cros-enterprise-psm and go/cros-client-psm for more details.
private_membership::rlwe::RlwePlaintextId ConstructDeviceRlweId(
const std::string& device_serial_number,
const std::string& device_rlz_brand_code);
// A class that handles all communications related to PSM protocol with
// DMServer. Also, upon successful determination, it caches the membership state
// of a given identifier in the local_state PrefService. Upon a failed
// determination it won't allow another membership check.
class PsmHelper;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class PsmStatus {
kAttempt = 0,
kSuccessfulDetermination = 1,
kError = 2,
kTimeout = 3,
kMaxValue = kTimeout,
};
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class PsmHashDanceComparison {
kEqualResults = 0,
kDifferentResults = 1,
kPSMErrorHashDanceSuccess = 2,
kPSMSuccessHashDanceError = 3,
kBothError = 4,
kMaxValue = kBothError,
};
// Indicates all possible different results of PSM and Hash dance protocols,
// after both protocols have executed successfully. These values are persisted
// to logs. Entries should not be renumbered and numeric values should never be
// reused.
enum class PsmHashDanceDifferentResultsComparison {
kHashDanceTruePsmFalse = 0,
kPsmTrueHashDanceFalse = 1,
kMaxValue = kPsmTrueHashDanceFalse,
};
// Interacts with the device management service and determines whether this
// machine should automatically enter the Enterprise Enrollment screen during
// OOBE.
class AutoEnrollmentClientImpl
: public AutoEnrollmentClient,
public network::NetworkConnectionTracker::NetworkConnectionObserver {
public:
// Subclasses of this class provide an identifier and specify the identifier
// set for the DeviceAutoEnrollmentRequest,
class DeviceIdentifierProvider;
// Subclasses of this class generate the request to download the device state
// (after determining that there is server-side device state) and parse the
// response.
class StateDownloadMessageProcessor;
class FactoryImpl : public Factory {
public:
FactoryImpl();
~FactoryImpl() override;
std::unique_ptr<AutoEnrollmentClient> CreateForFRE(
const ProgressCallback& progress_callback,
DeviceManagementService* device_management_service,
PrefService* local_state,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& server_backed_state_key,
int power_initial,
int power_limit) override;
std::unique_ptr<AutoEnrollmentClient> CreateForInitialEnrollment(
const ProgressCallback& progress_callback,
DeviceManagementService* device_management_service,
PrefService* local_state,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& device_serial_number,
const std::string& device_brand_code,
int power_initial,
int power_limit,
int power_outdated_server_detect) override;
private:
DISALLOW_COPY_AND_ASSIGN(FactoryImpl);
};
~AutoEnrollmentClientImpl() override;
// Registers preferences in local state.
static void RegisterPrefs(PrefRegistrySimple* registry);
void Start() override;
void Retry() override;
void CancelAndDeleteSoon() override;
std::string device_id() const override;
AutoEnrollmentState state() const override;
// network::NetworkConnectionTracker::NetworkConnectionObserver:
void OnConnectionChanged(network::mojom::ConnectionType type) override;
// Sets the PSM RLWE client for testing through |psm_helper_|, if the protocol
// is enabled. Also, the |psm_rlwe_client| has to be non-null.
void SetPsmRlweClientForTesting(
std::unique_ptr<private_membership::rlwe::PrivateMembershipRlweClient>
psm_rlwe_client,
const private_membership::rlwe::RlwePlaintextId& psm_rlwe_id);
private:
typedef bool (AutoEnrollmentClientImpl::*RequestCompletionHandler)(
policy::DeviceManagementService::Job*,
DeviceManagementStatus,
int,
const enterprise_management::DeviceManagementResponse&);
AutoEnrollmentClientImpl(
const ProgressCallback& progress_callback,
DeviceManagementService* device_management_service,
PrefService* local_state,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
std::unique_ptr<DeviceIdentifierProvider> device_identifier_provider,
std::unique_ptr<StateDownloadMessageProcessor>
state_download_message_processor,
int power_initial,
int power_limit,
base::Optional<int> power_outdated_server_detect,
std::string uma_suffix,
std::unique_ptr<PsmHelper> psm_helper);
// Tries to load the result of a previous execution of the protocol from
// local state. Returns true if that decision has been made and is valid.
bool GetCachedDecision();
// Kicks protocol processing, restarting the current step if applicable.
// Returns true if progress has been made, false if the protocol is done.
bool RetryStep();
// Retries running PSM protocol, if the protocol
// is enabled and it is possible to start. Returns true if the protocol is
// enabled or it's in progress, false if the protocol is done. Note that the
// PSM protocol is only performed once per OOBE flow.
bool PsmRetryStep();
// Cleans up and invokes |progress_callback_|.
void ReportProgress(AutoEnrollmentState state);
// Calls RetryStep() to make progress or determine that all is done. In the
// latter case, calls ReportProgress().
void NextStep();
// Sends an auto-enrollment check request to the device management service.
void SendBucketDownloadRequest();
// Sends a device state download request to the device management service.
void SendDeviceStateRequest();
// Runs the response handler for device management requests and calls
// NextStep().
void HandleRequestCompletion(
RequestCompletionHandler handler,
policy::DeviceManagementService::Job* job,
DeviceManagementStatus status,
int net_error,
const enterprise_management::DeviceManagementResponse& response);
// Parses the server response to a bucket download request.
bool OnBucketDownloadRequestCompletion(
policy::DeviceManagementService::Job* job,
DeviceManagementStatus status,
int net_error,
const enterprise_management::DeviceManagementResponse& response);
// Parses the server response to a device state request.
bool OnDeviceStateRequestCompletion(
policy::DeviceManagementService::Job* job,
DeviceManagementStatus status,
int net_error,
const enterprise_management::DeviceManagementResponse& response);
// Returns true if the identifier hash provided by
// |device_identifier_provider_| is contained in |hashes|.
bool IsIdHashInProtobuf(
const google::protobuf::RepeatedPtrField<std::string>& hashes);
// Updates UMA histograms for bucket download timings.
void UpdateBucketDownloadTimingHistograms();
// Updates the UMA histogram for successful hash dance.
void RecordHashDanceSuccessTimeHistogram();
// Records the UMA histogram comparing results of hash dance and PSM. This
// function should be called after PSM and hash dance requests finished.
void RecordPsmHashDanceComparison();
// Callback to invoke when the protocol generates a relevant event. This can
// be either successful completion or an error that requires external action.
ProgressCallback progress_callback_;
// Current state.
AutoEnrollmentState state_;
// Whether the hash bucket check succeeded, indicating that the server knows
// this device and might have keep state for it.
bool has_server_state_;
// Whether the download of server-kept device state completed successfully.
bool device_state_available_;
// Randomly generated device id for the auto-enrollment requests.
std::string device_id_;
// Power-of-2 modulus to try next.
int current_power_;
// Power of the maximum power-of-2 modulus that this client will accept from
// a retry response from the server.
int power_limit_;
// If set and the modulus requested by the server is higher than
// |1<<power_outdated_server_detect|, this client will assume that the server
// is outdated.
base::Optional<int> power_outdated_server_detect_;
// Number of requests for a different modulus received from the server.
// Used to determine if the server keeps asking for different moduli.
int modulus_updates_received_;
// Used to communicate with the device management service.
DeviceManagementService* device_management_service_;
// Indicates whether Hash dance i.e. DeviceAutoEnrollmentRequest or
// DeviceStateRetrievalRequest is in progress. Note that is not affected by
// PSM protocol, whether it's in progress or not.
std::unique_ptr<DeviceManagementService::Job> request_job_;
// PrefService where the protocol's results are cached.
PrefService* local_state_;
// The loader factory to use to perform the auto enrollment request.
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
// Specifies the identifier set and the hash of the device's current
// identifier.
std::unique_ptr<DeviceIdentifierProvider> device_identifier_provider_;
// Fills and parses state retrieval request / response.
std::unique_ptr<StateDownloadMessageProcessor>
state_download_message_processor_;
// Obtains the device state using PSM protocol.
std::unique_ptr<PsmHelper> psm_helper_;
// Times used to determine the duration of the protocol, and the extra time
// needed to complete after the signin was complete.
// If |hash_dance_time_start_| is not null, the protocol is still running.
// If |time_extra_start_| is not null, the protocol is still running but our
// owner has relinquished ownership.
base::TimeTicks hash_dance_time_start_;
base::TimeTicks time_extra_start_;
// The time when the bucket download part of the protocol started.
base::TimeTicks time_start_bucket_download_;
// The UMA histogram suffix. Will be ".ForcedReenrollment" for an
// |AutoEnrollmentClient| used for FRE and ".InitialEnrollment" for an
// |AutoEnrollmentclient| used for initial enrollment.
const std::string uma_suffix_;
// Whether this instance already recorded the comparison of PSM and hash
// dance. This is required because we do not want to record the result again
// on a hash dance retry.
bool recorded_psm_hash_dance_comparison_ = false;
DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentClientImpl);
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_AUTO_ENROLLMENT_CLIENT_IMPL_H_