blob: be6b9ae667e224118a3cc4f493dc6c8e6100e366 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_SERVICE_H_
#define CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_SERVICE_H_
#include <memory>
#include <string>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
#include "components/ownership/owner_settings_service.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/core/common/cloud/cloud_policy_validator.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "crypto/scoped_nss_types.h"
namespace ownership {
class OwnerKeyUtil;
class PublicKey;
} // namespace ownership
namespace policy {
namespace off_hours {
class DeviceOffHoursController;
} // namespace off_hours
} // namespace policy
namespace ash {
class SessionManagerOperation;
// Deals with the low-level interface to Chrome OS device settings. Device
// settings are stored in a protobuf that's protected by a cryptographic
// signature generated by a key in the device owner's possession. Key and
// settings are brokered by the session_manager daemon.
//
// The purpose of DeviceSettingsService is to keep track of the current key and
// settings blob. For reading and writing device settings, use CrosSettings
// instead, which provides a high-level interface that allows for manipulation
// of individual settings.
//
// DeviceSettingsService generates notifications for key and policy update
// events so interested parties can reload state as appropriate.
class DeviceSettingsService : public SessionManagerClient::Observer {
public:
// Indicates ownership status of the device (listed in upgrade order).
enum OwnershipStatus {
OWNERSHIP_UNKNOWN = 0,
// Not yet owned.
OWNERSHIP_NONE,
// Either consumer ownership, cloud management or Active Directory
// management.
OWNERSHIP_TAKEN
};
using OwnershipStatusCallback = base::OnceCallback<void(OwnershipStatus)>;
using PolicyDataCallback =
base::OnceCallback<void(enterprise_management::PolicyData*)>;
// Status codes for Load() and Store().
// These values are logged to UMA. Entries should not be renumbered and
// numeric values should never be reused. Please keep in sync with
// "DeviceSettingsStatus" in src/tools/metrics/histograms/enums.xml.
enum Status {
STORE_SUCCESS,
STORE_KEY_UNAVAILABLE, // Owner key not yet configured.
STORE_OPERATION_FAILED, // IPC to session_manager daemon failed.
STORE_NO_POLICY, // No settings blob present.
STORE_INVALID_POLICY, // Invalid settings blob (proto parse failed).
STORE_VALIDATION_ERROR, // Policy validation failure.
kMaxValue = STORE_VALIDATION_ERROR,
};
// Observer interface.
class Observer {
public:
virtual ~Observer();
// Indicates device ownership status changes. This is triggered upon every
// browser start since the transition from uninitialized (OWNERSHIP_UNKNOWN)
// to initialized (either of OWNERSHIP_{NONE,TAKEN}) also counts as an
// ownership change.
virtual void OwnershipStatusChanged();
// Gets called after updates to the device settings.
virtual void DeviceSettingsUpdated();
virtual void OnDeviceSettingsServiceShutdown();
};
// Manage singleton instance.
static void Initialize();
static bool IsInitialized();
static void Shutdown();
static DeviceSettingsService* Get();
// Returns a human-readable string describing |status|.
static const char* StatusToString(Status status);
// Creates a device settings service instance. This is meant for unit tests,
// production code uses the singleton returned by Get() above.
DeviceSettingsService();
DeviceSettingsService(const DeviceSettingsService&) = delete;
DeviceSettingsService& operator=(const DeviceSettingsService&) = delete;
~DeviceSettingsService() override;
// To be called on startup once threads are initialized and D-Bus is ready.
void SetSessionManager(SessionManagerClient* session_manager_client,
scoped_refptr<ownership::OwnerKeyUtil> owner_key_util);
// Prevents the service from making further calls to session_manager_client
// and stops any pending operations.
void UnsetSessionManager();
// Must only be used with a |device_mode| that has been read and verified by
// the InstallAttributes class.
void SetDeviceMode(policy::DeviceMode device_mode);
const enterprise_management::PolicyData* policy_data() const {
return policy_data_.get();
}
const enterprise_management::PolicyFetchResponse* policy_fetch_response()
const {
return policy_fetch_response_.get();
}
// Returns the currently active device settings. Returns nullptr if the device
// settings have not been retrieved from session_manager yet.
const enterprise_management::ChromeDeviceSettingsProto* device_settings()
const {
return device_settings_.get();
}
// Returns the currently used owner key.
scoped_refptr<ownership::PublicKey> GetPublicKey();
// Returns the status generated by the *last operation*.
// WARNING: It is not correct to take this method as an indication of whether
// DeviceSettingsService contains valid device settings. In order to answer
// that question, simply check whether device_settings() is different from
// nullptr.
Status status() const { return store_status_; }
// Returns the currently device off hours controller. The returned pointer is
// guaranteed to be non-null.
policy::off_hours::DeviceOffHoursController* device_off_hours_controller()
const {
return device_off_hours_controller_.get();
}
void SetDeviceOffHoursControllerForTesting(
std::unique_ptr<policy::off_hours::DeviceOffHoursController> controller);
// Triggers an attempt to pull the public half of the owner key from disk and
// load the device settings.
void Load();
// Attempts to load asynchronously the settings if they haven't been loaded
// already and no request is in the queue. The aim is to avoid additional
// request when not needed. Should NOT be used when the settings need to be
// renewed, like in invalidations flow or when an explicit request from user
// to reload is received.
void LoadIfNotPresent();
// Synchronously pulls the public key and loads the device settings.
void LoadImmediately();
// Stores a policy blob to session_manager. The result of the operation is
// reported through |callback|. If successful, the updated device settings are
// present in policy_data() and device_settings() when the callback runs.
void Store(std::unique_ptr<enterprise_management::PolicyFetchResponse> policy,
base::OnceClosure callback);
// Returns the ownership status. May return OWNERSHIP_UNKNOWN if the disk
// hasn't been checked yet.
OwnershipStatus GetOwnershipStatus();
// Determines the ownership status and reports the result to |callback|. This
// is guaranteed to never return OWNERSHIP_UNKNOWN.
void GetOwnershipStatusAsync(OwnershipStatusCallback callback);
// Checks whether we have the private owner key.
//
// DEPRECATED (ygorshenin@, crbug.com/433840): this method should
// not be used since private key is a profile-specific resource and
// should be checked and used in a profile-aware manner, through
// OwnerSettingsService.
bool HasPrivateOwnerKey();
// Sets the identity of the user that's interacting with the service. This is
// relevant only for writing settings through SignAndStore().
//
// TODO (ygorshenin@, crbug.com/433840): get rid of the method when
// write path for device settings will be removed from
// DeviceSettingsProvider and all existing clients will be switched
// to OwnerSettingsServiceAsh.
void InitOwner(const std::string& username,
const base::WeakPtr<ownership::OwnerSettingsService>&
owner_settings_service);
const std::string& GetUsername() const;
ownership::OwnerSettingsService* GetOwnerSettingsService() const;
// Mark that the device will establish consumer ownership. If the flag is set
// and ownership is not taken, policy reload will be deferred until InitOwner
// is called. So that the ownership status is flipped after the private part
// of owner is fully loaded.
void MarkWillEstablishConsumerOwnership();
// Returns whether the current user should take ownership of the device
// (effectively whether the user is the first consumer user on the device).
bool GetWillEstablishConsumerOwnership() const {
return will_establish_consumer_ownership_;
}
// Adds an observer.
void AddObserver(Observer* observer);
// Removes an observer.
void RemoveObserver(Observer* observer);
// SessionManagerClient::Observer:
void OwnerKeySet(bool success) override;
void PropertyChangeComplete(bool success) override;
private:
friend class OwnerSettingsServiceAsh;
// Enqueues a new operation. Takes ownership of |operation| and starts it
// right away if there is no active operation currently.
void Enqueue(std::unique_ptr<SessionManagerOperation> operation);
// Enqueues a load operation.
void EnqueueLoad(bool request_key_load);
// Makes sure there's a reload operation so changes to the settings (and key,
// in case |request_key_load| is set) are getting picked up.
void EnsureReload(bool request_key_load);
// Runs the next pending operation.
void StartNextOperation();
// Updates status, policy data and owner key from a finished operation.
void HandleCompletedOperation(base::OnceClosure callback,
SessionManagerOperation* operation,
Status status);
// Same as HandleCompletedOperation(), but also starts the next pending
// operation if available.
void HandleCompletedAsyncOperation(base::OnceClosure callback,
SessionManagerOperation* operation,
Status status);
// Helper method for GetOwnershipStatusAsync to avoid data race upon
// user sign-in.
void ValidateOwnershipStatusAndNotify(OwnershipStatusCallback callback);
// Run OwnershipStatusChanged() for observers.
void NotifyOwnershipStatusChanged() const;
// Run DeviceSettingsUpdated() for observers.
void NotifyDeviceSettingsUpdated() const;
// Processes pending callbacks from GetOwnershipStatusAsync().
void RunPendingOwnershipStatusCallbacks();
SessionManagerClient* session_manager_client_ = nullptr;
scoped_refptr<ownership::OwnerKeyUtil> owner_key_util_;
Status store_status_ = STORE_SUCCESS;
std::vector<OwnershipStatusCallback> pending_ownership_status_callbacks_;
std::string username_;
scoped_refptr<ownership::PublicKey> public_key_;
base::WeakPtr<ownership::OwnerSettingsService> owner_settings_service_;
// Ownership status before the current session manager operation.
OwnershipStatus previous_ownership_status_ = OWNERSHIP_UNKNOWN;
std::unique_ptr<enterprise_management::PolicyFetchResponse>
policy_fetch_response_;
std::unique_ptr<enterprise_management::PolicyData> policy_data_;
std::unique_ptr<enterprise_management::ChromeDeviceSettingsProto>
device_settings_;
policy::DeviceMode device_mode_ = policy::DEVICE_MODE_PENDING;
// The queue of pending operations. The first operation on the queue is
// currently active; it gets removed and destroyed once it completes.
base::circular_deque<std::unique_ptr<SessionManagerOperation>>
pending_operations_;
base::ObserverList<Observer>::Unchecked observers_;
// Whether the device will be establishing consumer ownership.
bool will_establish_consumer_ownership_ = false;
std::unique_ptr<policy::off_hours::DeviceOffHoursController>
device_off_hours_controller_;
base::WeakPtrFactory<DeviceSettingsService> weak_factory_{this};
};
// Helper class for tests. Initializes the DeviceSettingsService singleton on
// construction and tears it down again on destruction.
class ScopedTestDeviceSettingsService {
public:
ScopedTestDeviceSettingsService();
ScopedTestDeviceSettingsService(const ScopedTestDeviceSettingsService&) =
delete;
ScopedTestDeviceSettingsService& operator=(
const ScopedTestDeviceSettingsService&) = delete;
~ScopedTestDeviceSettingsService();
};
} // namespace ash
#endif // CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_SERVICE_H_