Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(768)

Side by Side Diff: chrome/browser/signin/profile_oauth2_token_service.cc

Issue 23382008: Making OAuth2TokenService multi-login aware, updating callers, minor fixes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing to include the update to ProfileSyncService: r224220 Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/signin/profile_oauth2_token_service.h" 5 #include "chrome/browser/signin/profile_oauth2_token_service.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h" 8 #include "base/message_loop/message_loop.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "base/time/time.h" 10 #include "base/time/time.h"
(...skipping 28 matching lines...) Expand all
39 } 39 }
40 40
41 std::string ApplyAccountIdPrefix(const std::string& account_id) { 41 std::string ApplyAccountIdPrefix(const std::string& account_id) {
42 return kAccountIdPrefix + account_id; 42 return kAccountIdPrefix + account_id;
43 } 43 }
44 44
45 std::string RemoveAccountIdPrefix(const std::string& prefixed_account_id) { 45 std::string RemoveAccountIdPrefix(const std::string& prefixed_account_id) {
46 return prefixed_account_id.substr(kAccountIdPrefixLength); 46 return prefixed_account_id.substr(kAccountIdPrefixLength);
47 } 47 }
48 48
49 std::string GetAccountId(Profile* profile) {
50 SigninManagerBase* signin_manager =
51 SigninManagerFactory::GetForProfileIfExists(profile);
52 return signin_manager ? signin_manager->GetAuthenticatedUsername() :
53 std::string();
54 }
55
56 } // namespace 49 } // namespace
57 50
58 ProfileOAuth2TokenService::ProfileOAuth2TokenService() 51 ProfileOAuth2TokenService::ProfileOAuth2TokenService()
59 : profile_(NULL), 52 : profile_(NULL),
60 web_data_service_request_(0), 53 web_data_service_request_(0),
61 last_auth_error_(GoogleServiceAuthError::NONE) { 54 last_auth_error_(GoogleServiceAuthError::NONE) {
62 } 55 }
63 56
64 ProfileOAuth2TokenService::~ProfileOAuth2TokenService() { 57 ProfileOAuth2TokenService::~ProfileOAuth2TokenService() {
65 DCHECK(!signin_global_error_.get()) << 58 DCHECK(!signin_global_error_.get()) <<
(...skipping 26 matching lines...) Expand all
92 85
93 void ProfileOAuth2TokenService::Shutdown() { 86 void ProfileOAuth2TokenService::Shutdown() {
94 DCHECK(profile_) << "Shutdown() called without matching call to Initialize()"; 87 DCHECK(profile_) << "Shutdown() called without matching call to Initialize()";
95 CancelAllRequests(); 88 CancelAllRequests();
96 signin_global_error_->RemoveProvider(this); 89 signin_global_error_->RemoveProvider(this);
97 GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError( 90 GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError(
98 signin_global_error_.get()); 91 signin_global_error_.get());
99 signin_global_error_.reset(); 92 signin_global_error_.reset();
100 } 93 }
101 94
102 std::string ProfileOAuth2TokenService::GetRefreshToken() { 95 std::string ProfileOAuth2TokenService::GetRefreshToken(
103 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 96 const std::string& account_id) {
104 if (!token_service || !token_service->HasOAuthLoginToken()) { 97 std::map<std::string, std::string>::const_iterator iter =
105 return std::string(); 98 refresh_tokens_.find(account_id);
106 } 99 if (iter != refresh_tokens_.end())
107 return token_service->GetOAuth2LoginRefreshToken(); 100 return iter->second;
101 return std::string();
108 } 102 }
109 103
110 net::URLRequestContextGetter* ProfileOAuth2TokenService::GetRequestContext() { 104 net::URLRequestContextGetter* ProfileOAuth2TokenService::GetRequestContext() {
111 return profile_->GetRequestContext(); 105 return profile_->GetRequestContext();
112 } 106 }
113 107
114 void ProfileOAuth2TokenService::UpdateAuthError( 108 void ProfileOAuth2TokenService::UpdateAuthError(
109 const std::string& account_id,
115 const GoogleServiceAuthError& error) { 110 const GoogleServiceAuthError& error) {
111 // TODO(fgorski): SigninGlobalError needs to be made multi-login aware.
116 // Do not report connection errors as these are not actually auth errors. 112 // Do not report connection errors as these are not actually auth errors.
117 // We also want to avoid masking a "real" auth error just because we 113 // We also want to avoid masking a "real" auth error just because we
118 // subsequently get a transient network error. 114 // subsequently get a transient network error.
119 if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) 115 if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED)
120 return; 116 return;
121 117
122 if (error.state() != last_auth_error_.state()) { 118 if (error.state() != last_auth_error_.state()) {
123 last_auth_error_ = error; 119 last_auth_error_ = error;
124 signin_global_error_->AuthStatusChanged(); 120 signin_global_error_->AuthStatusChanged();
125 } 121 }
126 } 122 }
127 123
128 void ProfileOAuth2TokenService::Observe( 124 void ProfileOAuth2TokenService::Observe(
129 int type, 125 int type,
130 const content::NotificationSource& source, 126 const content::NotificationSource& source,
131 const content::NotificationDetails& details) { 127 const content::NotificationDetails& details) {
128 const std::string& account_id = GetPrimaryAccountId();
132 switch (type) { 129 switch (type) {
133 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { 130 case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
134 TokenService::TokenAvailableDetails* tok_details = 131 TokenService::TokenAvailableDetails* tok_details =
135 content::Details<TokenService::TokenAvailableDetails>(details).ptr(); 132 content::Details<TokenService::TokenAvailableDetails>(details).ptr();
136 if (tok_details->service() == 133 if (tok_details->service() ==
137 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { 134 GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
138 // TODO(fgorski): Canceling all requests will not be correct in a 135 // TODO(fgorski): Work on removing this code altogether in favor of the
139 // multi-login environment. We should cancel only the requests related 136 // upgrade steps invoked by Initialize.
140 // to the token being replaced (old token for the same account_id). 137 // TODO(fgorski): Refresh token received that way is not persisted in
141 // Previous refresh token is not available at this point, but since 138 // the token DB.
142 // there are no other refresh tokens, we cancel all active requests. 139 CancelRequestsForAccount(account_id);
143 CancelAllRequests(); 140 ClearCacheForAccount(account_id);
144 ClearCache(); 141 refresh_tokens_[account_id] = tok_details->token();
145 UpdateAuthError(GoogleServiceAuthError::AuthErrorNone()); 142 UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
146 FireRefreshTokenAvailable(GetAccountId(profile_)); 143 FireRefreshTokenAvailable(account_id);
147 } 144 }
148 break; 145 break;
149 } 146 }
150 case chrome::NOTIFICATION_TOKENS_CLEARED: { 147 case chrome::NOTIFICATION_TOKENS_CLEARED: {
151 CancelAllRequests(); 148 CancelAllRequests();
152 ClearCache(); 149 ClearCache();
153 UpdateAuthError(GoogleServiceAuthError::AuthErrorNone()); 150 UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
154 FireRefreshTokensCleared();
155 break; 151 break;
156 } 152 }
157 case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: 153 case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED:
158 // During startup, if the user is signed in and the OAuth2 refresh token 154 // During startup, if the user is signed in and the OAuth2 refresh token
159 // is empty, flag it as an error by badging the menu. Otherwise, if the 155 // is empty, flag it as an error by badging the menu. Otherwise, if the
160 // user goes on to set up sync, they will have to make two attempts: 156 // user goes on to set up sync, they will have to make two attempts:
161 // One to surface the OAuth2 error, and a second one after signing in. 157 // One to surface the OAuth2 error, and a second one after signing in.
162 // See crbug.com/276650. 158 // See crbug.com/276650.
163 if (!GetAccountId(profile_).empty() && GetRefreshToken().empty()) { 159 if (!account_id.empty() && GetRefreshToken(account_id).empty()) {
164 UpdateAuthError(GoogleServiceAuthError( 160 UpdateAuthError(account_id, GoogleServiceAuthError(
165 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 161 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
166 } 162 }
167 FireRefreshTokensLoaded(); 163 FireRefreshTokensLoaded();
168 break; 164 break;
169 default: 165 default:
170 NOTREACHED() << "Invalid notification type=" << type; 166 NOTREACHED() << "Invalid notification type=" << type;
171 break; 167 break;
172 } 168 }
173 } 169 }
174 170
175 GoogleServiceAuthError ProfileOAuth2TokenService::GetAuthStatus() const { 171 GoogleServiceAuthError ProfileOAuth2TokenService::GetAuthStatus() const {
176 return last_auth_error_; 172 return last_auth_error_;
177 } 173 }
178 174
179 void ProfileOAuth2TokenService::RegisterCacheEntry( 175 std::string ProfileOAuth2TokenService::GetPrimaryAccountId() {
180 const std::string& client_id, 176 SigninManagerBase* signin_manager =
181 const std::string& refresh_token, 177 SigninManagerFactory::GetForProfileIfExists(profile_);
182 const ScopeSet& scopes, 178 // TODO(fgorski): DCHECK(signin_manager) here - it may require update to test
183 const std::string& access_token, 179 // code and the line above (SigninManager might not exist yet).
184 const base::Time& expiration_date) { 180 return signin_manager ? signin_manager->GetAuthenticatedUsername()
185 if (ShouldCacheForRefreshToken(TokenServiceFactory::GetForProfile(profile_), 181 : std::string();
186 refresh_token)) {
187 OAuth2TokenService::RegisterCacheEntry(client_id,
188 refresh_token,
189 scopes,
190 access_token,
191 expiration_date);
192 }
193 } 182 }
194 183
195 bool ProfileOAuth2TokenService::ShouldCacheForRefreshToken( 184 std::vector<std::string> ProfileOAuth2TokenService::GetAccounts() {
196 TokenService *token_service, 185 std::vector<std::string> account_ids;
197 const std::string& refresh_token) { 186 for (std::map<std::string, std::string>::const_iterator iter =
198 if (!token_service || 187 refresh_tokens_.begin(); iter != refresh_tokens_.end(); ++iter) {
199 !token_service->HasOAuthLoginToken() || 188 account_ids.push_back(iter->first);
200 token_service->GetOAuth2LoginRefreshToken().compare(refresh_token) != 0) {
201 DLOG(INFO) <<
202 "Received a token with a refresh token not maintained by TokenService.";
203 return false;
204 } 189 }
205 return true; 190 return account_ids;
206 } 191 }
207 192
208 void ProfileOAuth2TokenService::UpdateCredentials( 193 void ProfileOAuth2TokenService::UpdateCredentials(
209 const std::string& account_id, 194 const std::string& account_id,
210 const std::string& refresh_token) { 195 const std::string& refresh_token) {
211 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 196 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
212 DCHECK(!refresh_token.empty()); 197 DCHECK(!refresh_token.empty());
213 198
214 bool refresh_token_present = refresh_tokens_.count(account_id) > 0; 199 bool refresh_token_present = refresh_tokens_.count(account_id) > 0;
215 if (!refresh_token_present || 200 if (!refresh_token_present ||
216 refresh_tokens_[account_id] != refresh_token) { 201 refresh_tokens_[account_id] != refresh_token) {
217 // If token present, and different from the new one, cancel its requests. 202 // If token present, and different from the new one, cancel its requests,
218 if (refresh_token_present) 203 // and clear the entries in cache related to that account.
219 CancelRequestsForToken(refresh_tokens_[account_id]); 204 if (refresh_token_present) {
205 CancelRequestsForAccount(account_id);
206 ClearCacheForAccount(account_id);
207 }
220 208
221 // Save the token in memory and in persistent store. 209 // Save the token in memory and in persistent store.
222 refresh_tokens_[account_id] = refresh_token; 210 refresh_tokens_[account_id] = refresh_token;
223 scoped_refptr<TokenWebData> token_web_data = 211 PersistCredentials(account_id, refresh_token);
224 TokenWebData::FromBrowserContext(profile_);
225 if (token_web_data.get())
226 token_web_data->SetTokenForService(ApplyAccountIdPrefix(account_id),
227 refresh_token);
228 212
213 UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
229 FireRefreshTokenAvailable(account_id); 214 FireRefreshTokenAvailable(account_id);
230 // TODO(fgorski): Notify diagnostic observers. 215 // TODO(fgorski): Notify diagnostic observers.
231 } 216 }
232 } 217 }
233 218
234 void ProfileOAuth2TokenService::RevokeCredentials( 219 void ProfileOAuth2TokenService::RevokeCredentials(
235 const std::string& account_id) { 220 const std::string& account_id) {
236 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 221 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
237 222
238 if (refresh_tokens_.count(account_id) > 0) { 223 if (refresh_tokens_.count(account_id) > 0) {
239 CancelRequestsForToken(refresh_tokens_[account_id]); 224 CancelRequestsForAccount(account_id);
225 ClearCacheForAccount(account_id);
240 refresh_tokens_.erase(account_id); 226 refresh_tokens_.erase(account_id);
241 scoped_refptr<TokenWebData> token_web_data = 227 ClearPersistedCredentials(account_id);
242 TokenWebData::FromBrowserContext(profile_);
243 if (token_web_data.get())
244 token_web_data->RemoveTokenForService(ApplyAccountIdPrefix(account_id));
245 FireRefreshTokenRevoked(account_id); 228 FireRefreshTokenRevoked(account_id);
246 229
247 // TODO(fgorski): Notify diagnostic observers. 230 // TODO(fgorski): Notify diagnostic observers.
248 } 231 }
249 } 232 }
250 233
234 void ProfileOAuth2TokenService::PersistCredentials(
235 const std::string& account_id,
236 const std::string& refresh_token) {
237 scoped_refptr<TokenWebData> token_web_data =
238 TokenWebData::FromBrowserContext(profile_);
239 if (token_web_data.get()) {
240 token_web_data->SetTokenForService(ApplyAccountIdPrefix(account_id),
241 refresh_token);
242 }
243 }
244
245 void ProfileOAuth2TokenService::ClearPersistedCredentials(
246 const std::string& account_id) {
247 scoped_refptr<TokenWebData> token_web_data =
248 TokenWebData::FromBrowserContext(profile_);
249 if (token_web_data.get())
250 token_web_data->RemoveTokenForService(ApplyAccountIdPrefix(account_id));
251 }
252
251 void ProfileOAuth2TokenService::RevokeAllCredentials() { 253 void ProfileOAuth2TokenService::RevokeAllCredentials() {
252 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 254 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
253 255
254 CancelAllRequests(); 256 CancelAllRequests();
255 for (std::map<std::string, std::string>::const_iterator iter = 257 for (std::map<std::string, std::string>::const_iterator iter =
256 refresh_tokens_.begin(); 258 refresh_tokens_.begin();
257 iter != refresh_tokens_.end(); 259 iter != refresh_tokens_.end();
258 ++iter) { 260 ++iter) {
259 FireRefreshTokenRevoked(iter->first); 261 FireRefreshTokenRevoked(iter->first);
260 } 262 }
261 refresh_tokens_.clear(); 263 refresh_tokens_.clear();
262 264
263 scoped_refptr<TokenWebData> token_web_data = 265 scoped_refptr<TokenWebData> token_web_data =
264 TokenWebData::FromBrowserContext(profile_); 266 TokenWebData::FromBrowserContext(profile_);
265 if (token_web_data.get()) 267 if (token_web_data.get())
266 token_web_data->RemoveAllTokens(); 268 token_web_data->RemoveAllTokens();
267 FireRefreshTokensCleared();
268 269
269 // TODO(fgorski): Notify diagnostic observers. 270 // TODO(fgorski): Notify diagnostic observers.
270 } 271 }
271 272
272 void ProfileOAuth2TokenService::LoadCredentials() { 273 void ProfileOAuth2TokenService::LoadCredentials() {
273 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 274 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
274 DCHECK_EQ(0, web_data_service_request_); 275 DCHECK_EQ(0, web_data_service_request_);
275 276
276 CancelAllRequests(); 277 CancelAllRequests();
277 refresh_tokens_.clear(); 278 refresh_tokens_.clear();
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 } else { 320 } else {
320 DCHECK(!refresh_token.empty()); 321 DCHECK(!refresh_token.empty());
321 std::string account_id = RemoveAccountIdPrefix(prefixed_account_id); 322 std::string account_id = RemoveAccountIdPrefix(prefixed_account_id);
322 refresh_tokens_[account_id] = refresh_token; 323 refresh_tokens_[account_id] = refresh_token;
323 FireRefreshTokenAvailable(account_id); 324 FireRefreshTokenAvailable(account_id);
324 // TODO(fgorski): Notify diagnostic observers. 325 // TODO(fgorski): Notify diagnostic observers.
325 } 326 }
326 } 327 }
327 328
328 if (!old_login_token.empty() && 329 if (!old_login_token.empty() &&
329 refresh_tokens_.count(GetAccountId(profile_)) == 0) { 330 refresh_tokens_.count(GetPrimaryAccountId()) == 0) {
330 UpdateCredentials(GetAccountId(profile_), old_login_token); 331 UpdateCredentials(GetPrimaryAccountId(), old_login_token);
331 } 332 }
332 333
333 FireRefreshTokensLoaded(); 334 FireRefreshTokensLoaded();
334 } 335 }
OLDNEW
« no previous file with comments | « chrome/browser/signin/profile_oauth2_token_service.h ('k') | chrome/browser/signin/profile_oauth2_token_service_request.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698