1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_TRUSTED_VAULT_STANDALONE_TRUSTED_VAULT_BACKEND_H_
#define COMPONENTS_TRUSTED_VAULT_STANDALONE_TRUSTED_VAULT_BACKEND_H_
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/trusted_vault/local_recovery_factor.h"
#include "components/trusted_vault/proto/local_trusted_vault.pb.h"
#include "components/trusted_vault/standalone_trusted_vault_storage.h"
#include "components/trusted_vault/trusted_vault_degraded_recoverability_handler.h"
#include "components/trusted_vault/trusted_vault_histograms.h"
#include "components/trusted_vault/trusted_vault_server_constants.h"
#include "components/trusted_vault/trusted_vault_throttling_connection.h"
#include "google_apis/gaia/gaia_id.h"
#include "google_apis/gaia/google_service_auth_error.h"
namespace signin {
class AccountsInCookieJarInfo;
} // namespace signin
namespace trusted_vault {
// Provides interfaces to store/remove keys to/from file storage.
// This class performs expensive operations and expected to be run from
// dedicated sequence (using thread pool). Can be constructed on any thread/
// sequence.
class StandaloneTrustedVaultBackend
: public base::RefCountedThreadSafe<StandaloneTrustedVaultBackend>,
public TrustedVaultDegradedRecoverabilityHandler::Delegate {
public:
using FetchKeysCallback = base::OnceCallback<void(
const std::vector<std::vector<uint8_t>>& vault_keys)>;
class Delegate {
public:
Delegate() = default;
Delegate(const Delegate&) = delete;
virtual ~Delegate() = default;
Delegate& operator=(const Delegate&) = delete;
virtual void NotifyRecoverabilityDegradedChanged() = 0;
};
class LocalRecoveryFactorsFactory {
public:
LocalRecoveryFactorsFactory() = default;
LocalRecoveryFactorsFactory(const LocalRecoveryFactorsFactory&) = delete;
virtual ~LocalRecoveryFactorsFactory() = default;
LocalRecoveryFactorsFactory& operator=(const LocalRecoveryFactorsFactory&) =
delete;
// Creates LocalRecoveryFactor's for |primary_account|.
// Note that the returned LocalRecoveryFactor's will keep a reference to
// |storage| and |connection|.
virtual std::vector<std::unique_ptr<LocalRecoveryFactor>>
CreateLocalRecoveryFactors(SecurityDomainId security_domain_id,
StandaloneTrustedVaultStorage* storage,
TrustedVaultThrottlingConnection* connection,
const CoreAccountInfo& primary_account) = 0;
};
enum class RefreshTokenErrorState {
// State can not be identified (e.g. refresh token is not loaded yet).
kUnknown,
// Refresh token is in persistent auth error state.
kPersistentAuthError,
// There are no persistent auth errors (note, that transient errors are
// still possible).
kNoPersistentAuthErrors,
};
// |connection| can be null, in this case functionality that involves
// interaction with vault service (such as recovery factor registration, keys
// downloading, etc.) will be disabled.
StandaloneTrustedVaultBackend(
#if BUILDFLAG(IS_MAC)
const std::string& icloud_keychain_access_group_prefix,
#endif
SecurityDomainId security_domain_id,
std::unique_ptr<StandaloneTrustedVaultStorage> storage,
std::unique_ptr<Delegate> delegate,
std::unique_ptr<TrustedVaultConnection> connection);
StandaloneTrustedVaultBackend(const StandaloneTrustedVaultBackend& other) =
delete;
StandaloneTrustedVaultBackend& operator=(
const StandaloneTrustedVaultBackend& other) = delete;
// TrustedVaultDegradedRecoverabilityHandler::Delegate implementation.
void WriteDegradedRecoverabilityState(
const trusted_vault_pb::LocalTrustedVaultDegradedRecoverabilityState&
degraded_recoverability_state) override;
void OnDegradedRecoverabilityChanged() override;
// Restores state saved on disk, should be called before using the object.
void ReadDataFromDisk();
// Populates vault keys corresponding to |account_info| into |callback|. If
// recent keys are locally available, |callback| will be called immediately.
// Otherwise, attempts to download new keys from the server. In case of
// failure or if current state isn't sufficient it will populate locally
// available keys regardless of their freshness.
void FetchKeys(const CoreAccountInfo& account_info,
FetchKeysCallback callback);
// Replaces keys for given |gaia_id| both in memory and on disk.
void StoreKeys(const GaiaId& gaia_id,
const std::vector<std::vector<uint8_t>>& keys,
int last_key_version);
// Marks vault keys as stale. Afterwards, the next FetchKeys() call for this
// |account_info| will trigger a key download attempt.
bool MarkLocalKeysAsStale(const CoreAccountInfo& account_info);
// Sets/resets |primary_account_|.
void SetPrimaryAccount(const std::optional<CoreAccountInfo>& primary_account,
RefreshTokenErrorState refresh_token_error_state);
// Handles changes of accounts in cookie jar and removes keys for some
// accounts:
// 1. Non-primary account keys are removed if account isn't in cookie jar.
// 2. Primary account keys marked for deferred deletion if account isn't in
// cookie jar.
void UpdateAccountsInCookieJarInfo(
const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info);
// Returns whether recoverability of the keys is degraded and user action is
// required to add a new method.
void GetIsRecoverabilityDegraded(const CoreAccountInfo& account_info,
base::OnceCallback<void(bool)> cb);
// Registers a new trusted recovery method that can be used to retrieve keys.
void AddTrustedRecoveryMethod(const GaiaId& gaia_id,
const std::vector<uint8_t>& public_key,
int method_type_hint,
base::OnceClosure cb);
void ClearLocalDataForAccount(const CoreAccountInfo& account_info);
std::optional<CoreAccountInfo> GetPrimaryAccountForTesting() const;
trusted_vault_pb::LocalDeviceRegistrationInfo
GetDeviceRegistrationInfoForTesting(const GaiaId& gaia_id);
std::vector<uint8_t> GetLastAddedRecoveryMethodPublicKeyForTesting() const;
int GetLastKeyVersionForTesting(const GaiaId& gaia_id);
bool HasPendingTrustedRecoveryMethodForTesting() const;
static scoped_refptr<StandaloneTrustedVaultBackend> CreateForTesting(
SecurityDomainId security_domain_id,
std::unique_ptr<StandaloneTrustedVaultStorage> storage,
std::unique_ptr<Delegate> delegate,
std::unique_ptr<TrustedVaultThrottlingConnection> connection,
std::unique_ptr<LocalRecoveryFactorsFactory>
local_recovery_factors_factory);
private:
friend class base::RefCountedThreadSafe<StandaloneTrustedVaultBackend>;
// Constructor which allows specifying a TrustedVaultThrottlingConnection and
// a LocalRecoveryFactorsFactory.
// Only used in tests.
StandaloneTrustedVaultBackend(
SecurityDomainId security_domain_id,
std::unique_ptr<StandaloneTrustedVaultStorage> storage,
std::unique_ptr<Delegate> delegate,
std::unique_ptr<TrustedVaultThrottlingConnection> connection,
std::unique_ptr<LocalRecoveryFactorsFactory>
local_recovery_factors_factory);
static TrustedVaultDownloadKeysStatusForUMA
GetDownloadKeysStatusForUMAFromResponse(
TrustedVaultDownloadKeysStatus response_status);
~StandaloneTrustedVaultBackend() override;
// Attempts to register local recovery factors in case they're not yet
// registered and currently available local data is sufficient to do it. Also
// records registration related metrics.
void MaybeRegisterLocalRecoveryFactors();
// Attempts to honor the pending operation stored in
// |pending_trusted_recovery_method_|.
void MaybeProcessPendingTrustedRecoveryMethod();
// Called when registration of a local recovery factor for |gaia_id| is
// completed (either successfully or not). |storage_| must contain
// LocalTrustedVaultPerUser for given |gaia_id|.
void OnRecoveryFactorRegistered(
LocalRecoveryFactorType local_recovery_factor_type,
TrustedVaultRegistrationStatus status,
int key_version,
bool had_local_keys);
void AttemptRecoveryFactor(size_t local_recovery_factor);
void OnKeysRecovered(size_t current_local_recovery_factor,
LocalRecoveryFactor::RecoveryStatus status,
const std::vector<std::vector<uint8_t>>& new_vault_keys,
int last_vault_key_version);
void OnTrustedRecoveryMethodAdded(base::OnceClosure cb);
// Invokes |callback| with currently available keys for |gaia_id|.
void FulfillFetchKeys(
const GaiaId& gaia_id,
FetchKeysCallback callback,
std::optional<TrustedVaultRecoverKeysOutcomeForUMA> status_for_uma);
// Same as above, but takes parameters from |ongoing_fetch_keys|, used when
// keys are fetched asynchronously, after keys downloading attempt.
void FulfillOngoingFetchKeys(
std::optional<TrustedVaultRecoverKeysOutcomeForUMA> status_for_uma);
// Removes all data for non-primary accounts if they were previously marked
// for deletion due to accounts in cookie jar changes.
void RemoveNonPrimaryAccountKeysIfMarkedForDeletion();
const SecurityDomainId security_domain_id_;
const std::unique_ptr<StandaloneTrustedVaultStorage> storage_;
const std::unique_ptr<Delegate> delegate_;
// Used for communication with trusted vault server. Can be null, in this case
// functionality that involves interaction with vault service (such as
// recovery factor registration, keys downloading, etc.) will be disabled.
// Note: |connection_| depends on |storage_|, so it needs to be destroyed
// first. Thus, the field order matters.
// TODO(crbug.com/40143544): |connection_| can be null if URL passed as
// kTrustedVaultServiceURLSwitch is not valid, consider making it non-nullable
// even in this case and clean up related logic.
const std::unique_ptr<TrustedVaultThrottlingConnection> connection_;
// Only current |primary_account_| can be used for communication with trusted
// vault server.
std::optional<CoreAccountInfo> primary_account_;
// Factory to create |local_recovery_factors_|. Can be overwritten in tests.
const std::unique_ptr<LocalRecoveryFactorsFactory>
local_recovery_factors_factory_;
// All known local recovery factors that can be used to attempt key recovery.
// Note: |local_recovery_factors_| depends on |storage_|, thus it must be
// destroyed before |storage_| (i.e. the order of the fields matters).
std::vector<std::unique_ptr<LocalRecoveryFactor>> local_recovery_factors_;
// Error state of refresh token for |primary_account_|.
RefreshTokenErrorState refresh_token_error_state_ =
StandaloneTrustedVaultBackend::RefreshTokenErrorState::kUnknown;
// If AddTrustedRecoveryMethod() gets invoked before SetPrimaryAccount(), the
// execution gets deferred until SetPrimaryAccount() is invoked.
struct PendingTrustedRecoveryMethod {
PendingTrustedRecoveryMethod();
PendingTrustedRecoveryMethod(PendingTrustedRecoveryMethod&) = delete;
PendingTrustedRecoveryMethod& operator=(PendingTrustedRecoveryMethod&) =
delete;
PendingTrustedRecoveryMethod(PendingTrustedRecoveryMethod&&);
PendingTrustedRecoveryMethod& operator=(PendingTrustedRecoveryMethod&&);
~PendingTrustedRecoveryMethod();
GaiaId gaia_id;
std::vector<uint8_t> public_key;
int method_type_hint;
base::OnceClosure completion_callback;
};
std::optional<PendingTrustedRecoveryMethod> pending_trusted_recovery_method_;
// Keys fetching is asynchronous when it involves sending request to the
// server, this structure encapsulates the data needed to process the response
// and allow concurrent key fetches for the same user. Destroying this will
// cancel the ongoing request.
// Note, that |gaia_id| should match |primary_account_|. It is used only for
// verification.
struct OngoingFetchKeys {
OngoingFetchKeys();
OngoingFetchKeys(OngoingFetchKeys&) = delete;
OngoingFetchKeys& operator=(OngoingFetchKeys&) = delete;
OngoingFetchKeys(OngoingFetchKeys&&);
OngoingFetchKeys& operator=(OngoingFetchKeys&&);
~OngoingFetchKeys();
GaiaId gaia_id;
std::vector<FetchKeysCallback> callbacks;
};
std::optional<OngoingFetchKeys> ongoing_fetch_keys_;
// Same as above, but specifically used for recoverability-related requests.
// TODO(crbug.com/40178774): Move elsewhere.
std::unique_ptr<TrustedVaultConnection::Request>
ongoing_add_recovery_method_request_;
// Used to take care of polling the degraded recoverability state from the
// server for the |primary_account|. Instance changes whenever
// |primary_account| changes.
std::unique_ptr<TrustedVaultDegradedRecoverabilityHandler>
degraded_recoverability_handler_;
std::vector<uint8_t> last_added_recovery_method_public_key_for_testing_;
bool recovery_factor_registration_state_recorded_to_uma_ = false;
// If GetIsRecoverabilityDegraded() gets invoked before
// SetPrimaryAccount(), the execution gets deferred until
// SetPrimaryAccount() is invoked. This is possible because
// SetPrimaryAccount() is called only once refresh token are loaded and
// GetIsRecoverabilityDegraded() could be invoked before that.
struct PendingGetIsRecoverabilityDegraded {
PendingGetIsRecoverabilityDegraded();
PendingGetIsRecoverabilityDegraded(PendingGetIsRecoverabilityDegraded&) =
delete;
PendingGetIsRecoverabilityDegraded& operator=(
PendingGetIsRecoverabilityDegraded&) = delete;
PendingGetIsRecoverabilityDegraded(PendingGetIsRecoverabilityDegraded&&);
PendingGetIsRecoverabilityDegraded& operator=(
PendingGetIsRecoverabilityDegraded&&);
~PendingGetIsRecoverabilityDegraded();
CoreAccountInfo account_info;
base::OnceCallback<void(bool)> completion_callback;
};
std::optional<PendingGetIsRecoverabilityDegraded>
pending_get_is_recoverability_degraded_;
};
} // namespace trusted_vault
#endif // COMPONENTS_TRUSTED_VAULT_STANDALONE_TRUSTED_VAULT_BACKEND_H_
|