File: sync_auth_manager.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (229 lines) | stat: -rw-r--r-- 9,643 bytes parent folder | download | duplicates (5)
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
// 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.

#ifndef COMPONENTS_SYNC_SERVICE_SYNC_AUTH_MANAGER_H_
#define COMPONENTS_SYNC_SERVICE_SYNC_AUTH_MANAGER_H_

#include <memory>
#include <string>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/sync/engine/connection_status.h"
#include "components/sync/service/sync_token_status.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "net/base/backoff_entry.h"

namespace signin {
class AccessTokenFetcher;
struct AccessTokenInfo;
}  // namespace signin

namespace syncer {

struct SyncCredentials;

struct SyncAccountInfo {
  CoreAccountInfo account_info;
  bool is_sync_consented = false;
};

// SyncAuthManager tracks the account to be used for Sync and its authentication
// state. Note that this account may or may not be the primary account (as per
// IdentityManager::GetPrimaryAccountInfo() etc).
class SyncAuthManager : public signin::IdentityManager::Observer {
 public:
  class Delegate {
   public:
    virtual ~Delegate() = default;

    // Called when the existence of an authenticated account changes. It's
    // guaranteed that this is only called for going from "no account" to "have
    // account" or vice versa, or if the existing account's `is_primary` bit
    // changed. I.e. SyncAuthManager will never directly switch from one account
    // to a different one. Call GetActiveAccountInfo to get the new state.
    virtual void SyncAuthAccountStateChanged() = 0;

    // Called when the credential state changes, i.e. an access token was
    // added/changed/removed. Call GetCredentials to get the new state.
    virtual void SyncAuthCredentialsChanged() = 0;
  };

  // `identity_manager` may be null (this is the case if local Sync is enabled),
  // but if non-null, must outlive this object. `delegate` must not be null and
  // must outlive this object.
  SyncAuthManager(signin::IdentityManager* identity_manager,
                  Delegate* delegate);

  SyncAuthManager(const SyncAuthManager&) = delete;
  SyncAuthManager& operator=(const SyncAuthManager&) = delete;

  ~SyncAuthManager() override;

  // Tells the tracker to start listening for changes to the account/sign-in
  // status. This gets called during SyncService initialization, except in the
  // case of local Sync. Before this is called, GetActiveAccountInfo will always
  // return an empty AccountInfo. Note that this will *not* trigger any
  // callbacks, even if there is an active account afterwards.
  void RegisterForAuthNotifications();

  // Returns whether all relevant account information as returned by
  // GetActiveAccountInfo() has been fully loaded.
  bool IsActiveAccountInfoFullyLoaded() const;

  // Returns the account which should be used when communicating with the Sync
  // server. Note that this account may not be blessed for Sync-the-feature.
  SyncAccountInfo GetActiveAccountInfo() const;

  // Returns the last auth error that was encountered. The error could have come
  // from the Sync server or from the IdentityManager.
  GoogleServiceAuthError GetLastAuthError() const;

  // Returns the time at which the last auth error was set.
  base::Time GetLastAuthErrorTime() const;

  // Returns whether we are in the "Sync paused" state. That means there is a
  // primary account, but the user signed out in the content area, and so we
  // don't have credentials for it anymore.
  bool IsSyncPaused() const;

  // Returns the credentials to be passed to the SyncEngine.
  SyncCredentials GetCredentials() const;

  const std::string& access_token() const { return access_token_; }

  // Returns the state of the access token and token request, for display in
  // internals UI.
  SyncTokenStatus GetSyncTokenStatus() const;

  // Called by SyncServiceImpl when Sync starts up and will try talking to
  // the server soon. This initiates fetching an access token.
  void ConnectionOpened();

  // Called by SyncServiceImpl when the status of the connection to the Sync
  // server changed. Updates auth error state accordingly.
  void ConnectionStatusChanged(ConnectionStatus status);

  // Called by SyncServiceImpl when the connection to the Sync server is
  // closed (due to Sync being shut down). Clears all related state (such as
  // cached access token, error from the server, etc).
  void ConnectionClosed();

  // signin::IdentityManager::Observer implementation.
  void OnPrimaryAccountChanged(
      const signin::PrimaryAccountChangeEvent& event) override;
  void OnRefreshTokenUpdatedForAccount(
      const CoreAccountInfo& account_info) override;
  void OnRefreshTokenRemovedForAccount(
      const CoreAccountId& account_id) override;
  void OnErrorStateOfRefreshTokenUpdatedForAccount(
      const CoreAccountInfo& account_info,
      const GoogleServiceAuthError& error,
      signin_metrics::SourceForRefreshTokenOperation token_operation_source)
      override;
  void OnRefreshTokensLoaded() override;
  void OnIdentityManagerShutdown(
      signin::IdentityManager* identity_manager) override;

  // Test-only methods for inspecting/modifying internal state.
  bool IsRetryingAccessTokenFetchForTest() const;
  void ResetRequestAccessTokenBackoffForTest();

 private:
  SyncAccountInfo DetermineAccountToUse() const;

  // Updates `sync_account_` to the appropriate account (i.e.
  // DetermineAccountToUse) if necessary, and notifies observers of any changes
  // (sign-in/sign-out/"primary" bit change). Note that changing from one
  // account to another is exposed to observers as a sign-out + sign-in.
  // Returns whether the syncing account was updated.
  bool UpdateSyncAccountIfNecessary();

  // Invalidates any current access token, which means invalidating it with the
  // IdentityManager and also dropping our own cached copy. Meant to be called
  // when we know the current token is invalid (e.g. expired). Does not do
  // anything about any scheduled or ongoing request.
  void InvalidateAccessToken();

  // Clears any access token we have, and cancels any pending or scheduled
  // request for one.
  void ClearAccessTokenAndRequest();

  // Schedules a request for an access token according to the current
  // `request_access_token_backoff_`. Usually called after some transient error.
  void ScheduleAccessTokenRequest();

  // Immediately starts an access token request, unless one is already ongoing.
  // If another request is scheduled for later, it is canceled. Any access token
  // we currently have is invalidated.
  void RequestAccessToken();

  // Callback for `ongoing_access_token_fetch_`.
  void AccessTokenFetched(GoogleServiceAuthError error,
                          signin::AccessTokenInfo access_token_info);

  void SetLastAuthError(const GoogleServiceAuthError& error);

  const raw_ptr<signin::IdentityManager> identity_manager_;
  base::ScopedObservation<signin::IdentityManager,
                          signin::IdentityManager::Observer>
      identity_manager_observation_{this};
  const raw_ptr<Delegate> delegate_;

  bool registered_for_auth_notifications_ = false;

  // The account which we are using to sync. If this is non-empty, that does
  // *not* necessarily imply that Sync is actually running, e.g. because of
  // delayed startup.
  SyncAccountInfo sync_account_;

  // This is a cache of the last authentication response we received from
  // Chrome's identity/token management system.
  GoogleServiceAuthError last_auth_error_;
  base::Time last_auth_error_time_;

  // Whether Sync is currently connected to the server, i.e. ConnectionOpened()
  // has been called, but ConnectionClosed() hasn't. While this is false, we
  // don't try to get an access token. While it's true, we will *usually* have
  // either an access token or a pending/scheduled request for one, but this is
  // not guaranteed (e.g. in the case of a persistent auth error).
  bool connection_open_ = false;

  // The current access token. This is mutually exclusive with
  // `ongoing_access_token_fetch_` and `request_access_token_retry_timer_`:
  // We have at most one of a) an access token OR b) a pending request OR c) a
  // pending retry i.e. a scheduled request.
  std::string access_token_;

  // Pending request for an access token. Non-null iff there is a request
  // ongoing.
  std::unique_ptr<signin::AccessTokenFetcher> ongoing_access_token_fetch_;

  // If RequestAccessToken fails with transient error then retry requesting
  // access token with exponential backoff.
  base::OneShotTimer request_access_token_retry_timer_;
  net::BackoffEntry request_access_token_backoff_;

  // Info about the state of our access token, for display in the internals UI.
  // "Partial" because this instance is not fully populated - in particular,
  // `has_token` and `next_token_request_time` get computed on demand.
  SyncTokenStatus partial_token_status_;

  // Whether there was a retry done to fetch the access token when the request
  // was cancelled for the first time. This works around an issue that can only
  // happen once during browser startup, so it's sufficient to have a single
  // retry (i.e. not per request).
  bool access_token_retried_ = false;

  base::WeakPtrFactory<SyncAuthManager> weak_ptr_factory_{this};
};

}  // namespace syncer

#endif  // COMPONENTS_SYNC_SERVICE_SYNC_AUTH_MANAGER_H_