| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/net/gaia/token_service.h" | 5 #include "chrome/browser/net/gaia/token_service.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "chrome/browser/profiles/profile.h" | 9 #include "chrome/browser/profiles/profile.h" |
| 10 #include "chrome/common/chrome_notification_types.h" | 10 #include "chrome/common/chrome_notification_types.h" |
| 11 #include "chrome/common/chrome_switches.h" | 11 #include "chrome/common/chrome_switches.h" |
| 12 #include "chrome/common/net/gaia/gaia_auth_fetcher.h" | 12 #include "chrome/common/net/gaia/gaia_auth_fetcher.h" |
| 13 #include "chrome/common/net/gaia/gaia_constants.h" | 13 #include "chrome/common/net/gaia/gaia_constants.h" |
| 14 #include "content/browser/browser_thread.h" | 14 #include "content/browser/browser_thread.h" |
| 15 #include "content/common/notification_service.h" | 15 #include "content/common/notification_service.h" |
| 16 #include "content/common/notification_source.h" | 16 #include "content/common/notification_source.h" |
| 17 #include "net/url_request/url_request_context_getter.h" | 17 #include "net/url_request/url_request_context_getter.h" |
| 18 | 18 |
| 19 // Unfortunately kNumServices must be defined in the .h. | 19 // Unfortunately kNumServices must be defined in the .h. |
| 20 // TODO(chron): Sync doesn't use the TalkToken anymore so we can stop | 20 // TODO(chron): Sync doesn't use the TalkToken anymore so we can stop |
| 21 // requesting it. | 21 // requesting it. |
| 22 const char* TokenService::kServices[] = { | 22 const char* TokenService::kServices[] = { |
| 23 GaiaConstants::kGaiaService, | 23 GaiaConstants::kGaiaService, |
| 24 GaiaConstants::kSyncService, | 24 GaiaConstants::kSyncService, |
| 25 GaiaConstants::kTalkService, | 25 GaiaConstants::kTalkService, |
| 26 GaiaConstants::kDeviceManagementService | 26 GaiaConstants::kDeviceManagementService |
| 27 }; | 27 }; |
| 28 | 28 |
| 29 const char* kUnusedServiceScope = "unused-service-scope"; |
| 30 |
| 31 // Unfortunately kNumOAuthServices must be defined in the .h. |
| 32 // For OAuth, Chrome uses the OAuth2 service scope as the service name. |
| 33 const char* TokenService::kOAuthServices[] = { |
| 34 GaiaConstants::kSyncServiceOAuth, |
| 35 }; |
| 36 |
| 29 TokenService::TokenService() | 37 TokenService::TokenService() |
| 30 : token_loading_query_(0) { | 38 : profile_(NULL), |
| 39 token_loading_query_(0) { |
| 31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 40 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 32 } | 41 } |
| 33 | 42 |
| 34 TokenService::~TokenService() { | 43 TokenService::~TokenService() { |
| 35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 36 ResetCredentialsInMemory(); | 45 ResetCredentialsInMemory(); |
| 37 } | 46 } |
| 38 | 47 |
| 39 void TokenService::Initialize(const char* const source, | 48 void TokenService::Initialize(const char* const source, |
| 40 Profile* profile) { | 49 Profile* profile) { |
| 41 | 50 |
| 42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 43 if (!source_.empty()) { | 52 if (!source_.empty()) { |
| 44 // Already initialized. | 53 // Already initialized. |
| 45 return; | 54 return; |
| 46 } | 55 } |
| 56 DCHECK(!profile_); |
| 57 profile_ = profile; |
| 47 getter_ = profile->GetRequestContext(); | 58 getter_ = profile->GetRequestContext(); |
| 48 // Since the user can create a bookmark in incognito, sync may be running. | 59 // Since the user can create a bookmark in incognito, sync may be running. |
| 49 // Thus we have to go for explicit access. | 60 // Thus we have to go for explicit access. |
| 50 web_data_service_ = profile->GetWebDataService(Profile::EXPLICIT_ACCESS); | 61 web_data_service_ = profile->GetWebDataService(Profile::EXPLICIT_ACCESS); |
| 51 source_ = std::string(source); | 62 source_ = std::string(source); |
| 52 | 63 |
| 53 #ifndef NDEBUG | 64 #ifndef NDEBUG |
| 54 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 65 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
| 55 // Allow the token service to be cleared from the command line. | 66 // Allow the token service to be cleared from the command line. |
| 56 if (cmd_line->HasSwitch(switches::kClearTokenService)) | 67 if (cmd_line->HasSwitch(switches::kClearTokenService)) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 69 | 80 |
| 70 registrar_.Add(this, | 81 registrar_.Add(this, |
| 71 chrome::NOTIFICATION_TOKEN_UPDATED, | 82 chrome::NOTIFICATION_TOKEN_UPDATED, |
| 72 Source<Profile>(profile)); | 83 Source<Profile>(profile)); |
| 73 } | 84 } |
| 74 | 85 |
| 75 void TokenService::ResetCredentialsInMemory() { | 86 void TokenService::ResetCredentialsInMemory() { |
| 76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 77 | 88 |
| 78 // Terminate any running fetchers. Callbacks will not return. | 89 // Terminate any running fetchers. Callbacks will not return. |
| 79 for (int i = 0; i < kNumServices; i++) { | 90 for (int i = 0; i < kNumServices; ++i) { |
| 80 fetchers_[i].reset(); | 91 fetchers_[i].reset(); |
| 81 } | 92 } |
| 93 for (int i = 0; i < kNumOAuthServices; ++i) { |
| 94 oauth_fetchers_[i].reset(); |
| 95 } |
| 82 | 96 |
| 83 // Cancel pending loads. Callbacks will not return. | 97 // Cancel pending loads. Callbacks will not return. |
| 84 if (token_loading_query_) { | 98 if (token_loading_query_) { |
| 85 web_data_service_->CancelRequest(token_loading_query_); | 99 web_data_service_->CancelRequest(token_loading_query_); |
| 86 token_loading_query_ = 0; | 100 token_loading_query_ = 0; |
| 87 } | 101 } |
| 88 | 102 |
| 89 token_map_.clear(); | 103 token_map_.clear(); |
| 90 credentials_ = GaiaAuthConsumer::ClientLoginResult(); | 104 credentials_ = GaiaAuthConsumer::ClientLoginResult(); |
| 105 oauth_token_.clear(); |
| 106 oauth_secret_.clear(); |
| 91 } | 107 } |
| 92 | 108 |
| 93 void TokenService::UpdateCredentials( | 109 void TokenService::UpdateCredentials( |
| 94 const GaiaAuthConsumer::ClientLoginResult& credentials) { | 110 const GaiaAuthConsumer::ClientLoginResult& credentials) { |
| 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 96 credentials_ = credentials; | 112 credentials_ = credentials; |
| 97 | 113 |
| 98 SaveAuthTokenToDB(GaiaConstants::kGaiaLsid, credentials.lsid); | 114 SaveAuthTokenToDB(GaiaConstants::kGaiaLsid, credentials.lsid); |
| 99 SaveAuthTokenToDB(GaiaConstants::kGaiaSid, credentials.sid); | 115 SaveAuthTokenToDB(GaiaConstants::kGaiaSid, credentials.sid); |
| 100 | 116 |
| 101 // Cancels any currently running requests. | 117 // Cancels any currently running requests. |
| 102 for (int i = 0; i < kNumServices; i++) { | 118 for (int i = 0; i < kNumServices; i++) { |
| 103 fetchers_[i].reset(new GaiaAuthFetcher(this, source_, getter_)); | 119 fetchers_[i].reset(new GaiaAuthFetcher(this, source_, getter_)); |
| 104 } | 120 } |
| 105 } | 121 } |
| 106 | 122 |
| 123 void TokenService::UpdateOAuthCredentials( |
| 124 const std::string& oauth_token, |
| 125 const std::string& oauth_secret) { |
| 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 127 oauth_token_ = oauth_token; |
| 128 oauth_secret_ = oauth_secret; |
| 129 |
| 130 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuthToken, oauth_token); |
| 131 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuthSecret, oauth_secret); |
| 132 |
| 133 // Cancels any currently running requests. |
| 134 for (int i = 0; i < kNumOAuthServices; i++) { |
| 135 oauth_fetchers_[i].reset( |
| 136 new GaiaOAuthFetcher(this, getter_, profile_, kUnusedServiceScope)); |
| 137 } |
| 138 } |
| 139 |
| 107 void TokenService::LoadTokensFromDB() { | 140 void TokenService::LoadTokensFromDB() { |
| 108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 109 if (web_data_service_.get()) | 142 if (web_data_service_.get()) |
| 110 token_loading_query_ = web_data_service_->GetAllTokens(this); | 143 token_loading_query_ = web_data_service_->GetAllTokens(this); |
| 111 } | 144 } |
| 112 | 145 |
| 113 void TokenService::SaveAuthTokenToDB(const std::string& service, | 146 void TokenService::SaveAuthTokenToDB(const std::string& service, |
| 114 const std::string& auth_token) { | 147 const std::string& auth_token) { |
| 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 116 if (web_data_service_.get()) | 149 if (web_data_service_.get()) |
| 117 web_data_service_->SetTokenForService(service, auth_token); | 150 web_data_service_->SetTokenForService(service, auth_token); |
| 118 } | 151 } |
| 119 | 152 |
| 120 void TokenService::EraseTokensFromDB() { | 153 void TokenService::EraseTokensFromDB() { |
| 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 122 if (web_data_service_.get()) | 155 if (web_data_service_.get()) |
| 123 web_data_service_->RemoveAllTokens(); | 156 web_data_service_->RemoveAllTokens(); |
| 124 } | 157 } |
| 125 | 158 |
| 126 bool TokenService::AreCredentialsValid() const { | 159 bool TokenService::AreCredentialsValid() const { |
| 127 return !credentials_.lsid.empty() && !credentials_.sid.empty(); | 160 return !credentials_.lsid.empty() && !credentials_.sid.empty(); |
| 128 } | 161 } |
| 129 | 162 |
| 163 bool TokenService::AreOAuthCredentialsValid() const { |
| 164 return !oauth_token_.empty() && !oauth_secret_.empty(); |
| 165 } |
| 166 |
| 130 bool TokenService::HasLsid() const { | 167 bool TokenService::HasLsid() const { |
| 131 return !credentials_.lsid.empty(); | 168 return !credentials_.lsid.empty(); |
| 132 } | 169 } |
| 133 | 170 |
| 134 const std::string& TokenService::GetLsid() const { | 171 const std::string& TokenService::GetLsid() const { |
| 135 return credentials_.lsid; | 172 return credentials_.lsid; |
| 136 } | 173 } |
| 137 | 174 |
| 138 void TokenService::StartFetchingTokens() { | 175 void TokenService::StartFetchingTokens() { |
| 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 140 DCHECK(AreCredentialsValid()); | 177 DCHECK(AreCredentialsValid()); |
| 141 for (int i = 0; i < kNumServices; i++) { | 178 for (int i = 0; i < kNumServices; i++) { |
| 142 fetchers_[i]->StartIssueAuthToken(credentials_.sid, | 179 fetchers_[i]->StartIssueAuthToken(credentials_.sid, |
| 143 credentials_.lsid, | 180 credentials_.lsid, |
| 144 kServices[i]); | 181 kServices[i]); |
| 145 } | 182 } |
| 146 } | 183 } |
| 147 | 184 |
| 185 void TokenService::StartFetchingOAuthTokens() { |
| 186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 187 DCHECK(AreOAuthCredentialsValid()); |
| 188 for (int i = 0; i < kNumOAuthServices; i++) { |
| 189 oauth_fetchers_[i]->StartOAuthWrapBridge(oauth_token_, |
| 190 oauth_secret_, |
| 191 GaiaConstants::kGaiaOAuthDuration, |
| 192 kOAuthServices[i]); |
| 193 } |
| 194 } |
| 195 |
| 148 // Services dependent on a token will check if a token is available. | 196 // Services dependent on a token will check if a token is available. |
| 149 // If it isn't, they'll go to sleep until they get a token event. | 197 // If it isn't, they'll go to sleep until they get a token event. |
| 150 bool TokenService::HasTokenForService(const char* const service) const { | 198 bool TokenService::HasTokenForService(const char* const service) const { |
| 151 return token_map_.count(service) > 0; | 199 return token_map_.count(service) > 0; |
| 152 } | 200 } |
| 153 | 201 |
| 154 const std::string& TokenService::GetTokenForService( | 202 const std::string& TokenService::GetTokenForService( |
| 155 const char* const service) const { | 203 const char* const service) const { |
| 156 | 204 |
| 157 if (token_map_.count(service) > 0) { | 205 if (token_map_.count(service) > 0) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 SaveAuthTokenToDB(service, auth_token); | 251 SaveAuthTokenToDB(service, auth_token); |
| 204 } | 252 } |
| 205 | 253 |
| 206 void TokenService::OnIssueAuthTokenFailure(const std::string& service, | 254 void TokenService::OnIssueAuthTokenFailure(const std::string& service, |
| 207 const GoogleServiceAuthError& error) { | 255 const GoogleServiceAuthError& error) { |
| 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 209 LOG(WARNING) << "Auth token issuing failed for service:" << service; | 257 LOG(WARNING) << "Auth token issuing failed for service:" << service; |
| 210 FireTokenRequestFailedNotification(service, error); | 258 FireTokenRequestFailedNotification(service, error); |
| 211 } | 259 } |
| 212 | 260 |
| 261 void TokenService::OnOAuthGetAccessTokenSuccess(const std::string& token, |
| 262 const std::string& secret) { |
| 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 264 VLOG(1) << "TokenService::OnOAuthGetAccessTokenSuccess"; |
| 265 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuthToken, token); |
| 266 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuthSecret, secret); |
| 267 UpdateOAuthCredentials(token, secret); |
| 268 } |
| 269 |
| 270 void TokenService::OnOAuthGetAccessTokenFailure( |
| 271 const GoogleServiceAuthError& error) { |
| 272 VLOG(1) << "TokenService::OnOAuthGetAccessTokenFailure"; |
| 273 } |
| 274 |
| 275 void TokenService::OnOAuthWrapBridgeSuccess(const std::string& service_scope, |
| 276 const std::string& token, |
| 277 const std::string& expires_in) { |
| 278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 279 VLOG(1) << "Got an access token for " << service_scope; |
| 280 token_map_[service_scope] = token; |
| 281 FireTokenAvailableNotification(service_scope, token); |
| 282 SaveAuthTokenToDB(service_scope, token); |
| 283 } |
| 284 |
| 285 void TokenService::OnOAuthWrapBridgeFailure( |
| 286 const std::string& service_scope, |
| 287 const GoogleServiceAuthError& error) { |
| 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 289 LOG(WARNING) << "Auth token issuing failed for service:" << service_scope; |
| 290 FireTokenRequestFailedNotification(service_scope, error); |
| 291 } |
| 292 |
| 213 void TokenService::OnWebDataServiceRequestDone(WebDataService::Handle h, | 293 void TokenService::OnWebDataServiceRequestDone(WebDataService::Handle h, |
| 214 const WDTypedResult* result) { | 294 const WDTypedResult* result) { |
| 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 216 DCHECK(token_loading_query_); | 296 DCHECK(token_loading_query_); |
| 217 token_loading_query_ = 0; | 297 token_loading_query_ = 0; |
| 218 | 298 |
| 219 // If the fetch failed, there will be no result. In that case, we just don't | 299 // If the fetch failed, there will be no result. In that case, we just don't |
| 220 // load any tokens at all from the DB. | 300 // load any tokens at all from the DB. |
| 221 if (result) { | 301 if (result) { |
| 222 DCHECK(result->GetType() == TOKEN_RESULT); | 302 DCHECK(result->GetType() == TOKEN_RESULT); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 if (db_tokens.count(GaiaConstants::kGaiaSid) > 0) | 350 if (db_tokens.count(GaiaConstants::kGaiaSid) > 0) |
| 271 sid = db_tokens.find(GaiaConstants::kGaiaSid)->second; | 351 sid = db_tokens.find(GaiaConstants::kGaiaSid)->second; |
| 272 | 352 |
| 273 if (!lsid.empty() && !sid.empty()) { | 353 if (!lsid.empty() && !sid.empty()) { |
| 274 UpdateCredentials(GaiaAuthConsumer::ClientLoginResult(sid, | 354 UpdateCredentials(GaiaAuthConsumer::ClientLoginResult(sid, |
| 275 lsid, | 355 lsid, |
| 276 std::string(), | 356 std::string(), |
| 277 std::string())); | 357 std::string())); |
| 278 } | 358 } |
| 279 } | 359 } |
| 360 |
| 361 for (int i = 0; i < kNumOAuthServices; i++) { |
| 362 // OnIssueAuthTokenSuccess should come from the same thread. |
| 363 // If a token is already present in the map, it could only have |
| 364 // come from a DB read or from IssueAuthToken. Since we should never |
| 365 // fetch from the DB twice in a browser session, it must be from |
| 366 // OnIssueAuthTokenSuccess, which is a live fetcher. |
| 367 // |
| 368 // Network fetched tokens take priority over DB tokens, so exclude tokens |
| 369 // which have already been loaded by the fetcher. |
| 370 if (!in_memory_tokens->count(kOAuthServices[i]) && |
| 371 db_tokens.count(kOAuthServices[i])) { |
| 372 std::string db_token = db_tokens.find(kOAuthServices[i])->second; |
| 373 if (!db_token.empty()) { |
| 374 VLOG(1) << "Loading " << kOAuthServices[i] << "token from DB: " |
| 375 << db_token; |
| 376 (*in_memory_tokens)[kOAuthServices[i]] = db_token; |
| 377 FireTokenAvailableNotification(kOAuthServices[i], db_token); |
| 378 // Failures are only for network errors. |
| 379 } |
| 380 } |
| 381 } |
| 382 |
| 383 if (oauth_token_.empty() && oauth_secret_.empty()) { |
| 384 // Look for GAIA OAuth1 access token and secret. If we have both, and the |
| 385 // current crendentials are empty, update the credentials. |
| 386 std::string oauth_token; |
| 387 std::string oauth_secret; |
| 388 |
| 389 if (db_tokens.count(GaiaConstants::kGaiaOAuthToken) > 0) |
| 390 oauth_token = db_tokens.find(GaiaConstants::kGaiaOAuthToken)->second; |
| 391 |
| 392 if (db_tokens.count(GaiaConstants::kGaiaOAuthSecret) > 0) |
| 393 oauth_secret = db_tokens.find(GaiaConstants::kGaiaOAuthSecret)->second; |
| 394 |
| 395 if (!oauth_token.empty() && !oauth_secret.empty()) { |
| 396 UpdateOAuthCredentials(oauth_token, oauth_secret); |
| 397 } |
| 398 } |
| 280 } | 399 } |
| 281 | 400 |
| 282 void TokenService::Observe(int type, | 401 void TokenService::Observe(int type, |
| 283 const NotificationSource& source, | 402 const NotificationSource& source, |
| 284 const NotificationDetails& details) { | 403 const NotificationDetails& details) { |
| 285 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_UPDATED); | 404 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_UPDATED); |
| 286 TokenAvailableDetails* tok_details = | 405 TokenAvailableDetails* tok_details = |
| 287 Details<TokenAvailableDetails>(details).ptr(); | 406 Details<TokenAvailableDetails>(details).ptr(); |
| 288 OnIssueAuthTokenSuccess(tok_details->service(), tok_details->token()); | 407 OnIssueAuthTokenSuccess(tok_details->service(), tok_details->token()); |
| 289 } | 408 } |
| OLD | NEW |