| 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" |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 if (web_data_service_.get()) | 153 if (web_data_service_.get()) |
| 154 web_data_service_->SetTokenForService(service, auth_token); | 154 web_data_service_->SetTokenForService(service, auth_token); |
| 155 } | 155 } |
| 156 | 156 |
| 157 void TokenService::EraseTokensFromDB() { | 157 void TokenService::EraseTokensFromDB() { |
| 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 159 if (web_data_service_.get()) | 159 if (web_data_service_.get()) |
| 160 web_data_service_->RemoveAllTokens(); | 160 web_data_service_->RemoveAllTokens(); |
| 161 } | 161 } |
| 162 | 162 |
| 163 // static |
| 164 int TokenService::GetServiceIndex(const std::string& service) { |
| 165 for (int i = 0; i < kNumServices; ++i) { |
| 166 if (kServices[i] == service) |
| 167 return i; |
| 168 } |
| 169 return -1; |
| 170 } |
| 171 |
| 163 bool TokenService::AreCredentialsValid() const { | 172 bool TokenService::AreCredentialsValid() const { |
| 164 return !credentials_.lsid.empty() && !credentials_.sid.empty(); | 173 return !credentials_.lsid.empty() && !credentials_.sid.empty(); |
| 165 } | 174 } |
| 166 | 175 |
| 167 bool TokenService::HasLsid() const { | 176 bool TokenService::HasLsid() const { |
| 168 return !credentials_.lsid.empty(); | 177 return !credentials_.lsid.empty(); |
| 169 } | 178 } |
| 170 | 179 |
| 171 const std::string& TokenService::GetLsid() const { | 180 const std::string& TokenService::GetLsid() const { |
| 172 return credentials_.lsid; | 181 return credentials_.lsid; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 const std::string& TokenService::GetTokenForService( | 241 const std::string& TokenService::GetTokenForService( |
| 233 const char* const service) const { | 242 const char* const service) const { |
| 234 | 243 |
| 235 if (token_map_.count(service) > 0) { | 244 if (token_map_.count(service) > 0) { |
| 236 // Note map[key] is not const. | 245 // Note map[key] is not const. |
| 237 return (*token_map_.find(service)).second; | 246 return (*token_map_.find(service)).second; |
| 238 } | 247 } |
| 239 return EmptyString(); | 248 return EmptyString(); |
| 240 } | 249 } |
| 241 | 250 |
| 251 bool TokenService::HasOAuthLoginToken() const { |
| 252 return HasTokenForService(GaiaConstants::kGaiaOAuth2LoginRefreshToken); |
| 253 } |
| 254 |
| 255 const std::string& TokenService::GetOAuth2LoginRefreshToken() const { |
| 256 return GetTokenForService(GaiaConstants::kGaiaOAuth2LoginRefreshToken); |
| 257 } |
| 258 |
| 259 const std::string& TokenService::GetOAuth2LoginAccessToken() const { |
| 260 return GetTokenForService(GaiaConstants::kGaiaOAuth2LoginAccessToken); |
| 261 } |
| 262 |
| 242 // Note that this can fire twice or more for any given service. | 263 // Note that this can fire twice or more for any given service. |
| 243 // It can fire once from the DB read, and then once from the initial | 264 // It can fire once from the DB read, and then once from the initial |
| 244 // fetcher. Future fetches can cause more notification firings. | 265 // fetcher. Future fetches can cause more notification firings. |
| 245 // The DB read will not however fire a notification if the fetcher | 266 // The DB read will not however fire a notification if the fetcher |
| 246 // returned first. So it's always safe to use the latest notification. | 267 // returned first. So it's always safe to use the latest notification. |
| 247 void TokenService::FireTokenAvailableNotification( | 268 void TokenService::FireTokenAvailableNotification( |
| 248 const std::string& service, | 269 const std::string& service, |
| 249 const std::string& auth_token) { | 270 const std::string& auth_token) { |
| 250 | 271 |
| 251 TokenAvailableDetails details(service, auth_token); | 272 TokenAvailableDetails details(service, auth_token); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 272 FireTokenAvailableNotification(service, auth_token); | 293 FireTokenAvailableNotification(service, auth_token); |
| 273 } | 294 } |
| 274 | 295 |
| 275 void TokenService::OnIssueAuthTokenSuccess(const std::string& service, | 296 void TokenService::OnIssueAuthTokenSuccess(const std::string& service, |
| 276 const std::string& auth_token) { | 297 const std::string& auth_token) { |
| 277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 278 VLOG(1) << "Got an authorization token for " << service; | 299 VLOG(1) << "Got an authorization token for " << service; |
| 279 token_map_[service] = auth_token; | 300 token_map_[service] = auth_token; |
| 280 FireTokenAvailableNotification(service, auth_token); | 301 FireTokenAvailableNotification(service, auth_token); |
| 281 SaveAuthTokenToDB(service, auth_token); | 302 SaveAuthTokenToDB(service, auth_token); |
| 303 // If we got ClientLogin token for "lso" service, then start fetching OAuth2 |
| 304 // login scoped token pair. |
| 305 if (service == GaiaConstants::kLSOService) { |
| 306 int index = GetServiceIndex(service); |
| 307 DCHECK_NE(-1, index); |
| 308 fetchers_[index]->StartOAuthLoginTokenFetch(auth_token); |
| 309 } |
| 282 } | 310 } |
| 283 | 311 |
| 284 void TokenService::OnIssueAuthTokenFailure(const std::string& service, | 312 void TokenService::OnIssueAuthTokenFailure(const std::string& service, |
| 285 const GoogleServiceAuthError& error) { | 313 const GoogleServiceAuthError& error) { |
| 286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 287 LOG(WARNING) << "Auth token issuing failed for service:" << service; | 315 LOG(WARNING) << "Auth token issuing failed for service:" << service; |
| 288 FireTokenRequestFailedNotification(service, error); | 316 FireTokenRequestFailedNotification(service, error); |
| 289 } | 317 } |
| 290 | 318 |
| 319 void TokenService::OnOAuthLoginTokenSuccess(const std::string& refresh_token, |
| 320 const std::string& access_token, |
| 321 int expires_in_secs) { |
| 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 323 VLOG(1) << "Got OAuth2 login token pair"; |
| 324 token_map_[GaiaConstants::kGaiaOAuth2LoginRefreshToken] = refresh_token; |
| 325 token_map_[GaiaConstants::kGaiaOAuth2LoginAccessToken] = access_token; |
| 326 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuth2LoginRefreshToken, |
| 327 refresh_token); |
| 328 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuth2LoginAccessToken, |
| 329 access_token); |
| 330 // We don't save expiration information for now. |
| 331 |
| 332 FireTokenAvailableNotification(GaiaConstants::kGaiaOAuth2LoginRefreshToken, |
| 333 refresh_token); |
| 334 } |
| 335 |
| 336 void TokenService::OnOAuthLoginTokenFailure( |
| 337 const GoogleServiceAuthError& error) { |
| 338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 339 LOG(WARNING) << "OAuth2 login token pair fetch failed:"; |
| 340 FireTokenRequestFailedNotification( |
| 341 GaiaConstants::kGaiaOAuth2LoginRefreshToken, error); |
| 342 } |
| 343 |
| 291 void TokenService::OnOAuthGetAccessTokenSuccess(const std::string& token, | 344 void TokenService::OnOAuthGetAccessTokenSuccess(const std::string& token, |
| 292 const std::string& secret) { | 345 const std::string& secret) { |
| 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 294 VLOG(1) << "TokenService::OnOAuthGetAccessTokenSuccess"; | 347 VLOG(1) << "TokenService::OnOAuthGetAccessTokenSuccess"; |
| 295 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuthToken, token); | 348 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuthToken, token); |
| 296 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuthSecret, secret); | 349 SaveAuthTokenToDB(GaiaConstants::kGaiaOAuthSecret, secret); |
| 297 UpdateOAuthCredentials(token, secret); | 350 UpdateOAuthCredentials(token, secret); |
| 298 } | 351 } |
| 299 | 352 |
| 300 void TokenService::OnOAuthGetAccessTokenFailure( | 353 void TokenService::OnOAuthGetAccessTokenFailure( |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 content::Source<TokenService>(this), | 394 content::Source<TokenService>(this), |
| 342 content::NotificationService::NoDetails()); | 395 content::NotificationService::NoDetails()); |
| 343 } | 396 } |
| 344 | 397 |
| 345 // Load tokens from the db_token map into the in memory token map. | 398 // Load tokens from the db_token map into the in memory token map. |
| 346 void TokenService::LoadTokensIntoMemory( | 399 void TokenService::LoadTokensIntoMemory( |
| 347 const std::map<std::string, std::string>& db_tokens, | 400 const std::map<std::string, std::string>& db_tokens, |
| 348 std::map<std::string, std::string>* in_memory_tokens) { | 401 std::map<std::string, std::string>* in_memory_tokens) { |
| 349 | 402 |
| 350 for (int i = 0; i < kNumServices; i++) { | 403 for (int i = 0; i < kNumServices; i++) { |
| 351 // OnIssueAuthTokenSuccess should come from the same thread. | 404 LoadSingleTokenIntoMemory(db_tokens, in_memory_tokens, kServices[i]); |
| 352 // If a token is already present in the map, it could only have | |
| 353 // come from a DB read or from IssueAuthToken. Since we should never | |
| 354 // fetch from the DB twice in a browser session, it must be from | |
| 355 // OnIssueAuthTokenSuccess, which is a live fetcher. | |
| 356 // | |
| 357 // Network fetched tokens take priority over DB tokens, so exclude tokens | |
| 358 // which have already been loaded by the fetcher. | |
| 359 if (!in_memory_tokens->count(kServices[i]) && | |
| 360 db_tokens.count(kServices[i])) { | |
| 361 std::string db_token = db_tokens.find(kServices[i])->second; | |
| 362 if (!db_token.empty()) { | |
| 363 VLOG(1) << "Loading " << kServices[i] << " token from DB: " << db_token; | |
| 364 (*in_memory_tokens)[kServices[i]] = db_token; | |
| 365 FireTokenAvailableNotification(kServices[i], db_token); | |
| 366 // Failures are only for network errors. | |
| 367 } | |
| 368 } | |
| 369 } | 405 } |
| 406 LoadSingleTokenIntoMemory(db_tokens, in_memory_tokens, |
| 407 GaiaConstants::kGaiaOAuth2LoginRefreshToken); |
| 408 LoadSingleTokenIntoMemory(db_tokens, in_memory_tokens, |
| 409 GaiaConstants::kGaiaOAuth2LoginAccessToken); |
| 370 | 410 |
| 371 if (credentials_.lsid.empty() && credentials_.sid.empty()) { | 411 if (credentials_.lsid.empty() && credentials_.sid.empty()) { |
| 372 // Look for GAIA SID and LSID tokens. If we have both, and the current | 412 // Look for GAIA SID and LSID tokens. If we have both, and the current |
| 373 // crendentials are empty, update the credentials. | 413 // crendentials are empty, update the credentials. |
| 374 std::string lsid; | 414 std::string lsid; |
| 375 std::string sid; | 415 std::string sid; |
| 376 | 416 |
| 377 if (db_tokens.count(GaiaConstants::kGaiaLsid) > 0) | 417 if (db_tokens.count(GaiaConstants::kGaiaLsid) > 0) |
| 378 lsid = db_tokens.find(GaiaConstants::kGaiaLsid)->second; | 418 lsid = db_tokens.find(GaiaConstants::kGaiaLsid)->second; |
| 379 | 419 |
| 380 if (db_tokens.count(GaiaConstants::kGaiaSid) > 0) | 420 if (db_tokens.count(GaiaConstants::kGaiaSid) > 0) |
| 381 sid = db_tokens.find(GaiaConstants::kGaiaSid)->second; | 421 sid = db_tokens.find(GaiaConstants::kGaiaSid)->second; |
| 382 | 422 |
| 383 if (!lsid.empty() && !sid.empty()) { | 423 if (!lsid.empty() && !sid.empty()) { |
| 384 UpdateCredentials(GaiaAuthConsumer::ClientLoginResult(sid, | 424 UpdateCredentials(GaiaAuthConsumer::ClientLoginResult(sid, |
| 385 lsid, | 425 lsid, |
| 386 std::string(), | 426 std::string(), |
| 387 std::string())); | 427 std::string())); |
| 388 } | 428 } |
| 389 } | 429 } |
| 390 | 430 |
| 391 for (int i = 0; i < kNumOAuthServices; i++) { | 431 for (int i = 0; i < kNumOAuthServices; i++) { |
| 392 // OnIssueAuthTokenSuccess should come from the same thread. | 432 LoadSingleTokenIntoMemory(db_tokens, in_memory_tokens, kOAuthServices[i]); |
| 393 // If a token is already present in the map, it could only have | |
| 394 // come from a DB read or from IssueAuthToken. Since we should never | |
| 395 // fetch from the DB twice in a browser session, it must be from | |
| 396 // OnIssueAuthTokenSuccess, which is a live fetcher. | |
| 397 // | |
| 398 // Network fetched tokens take priority over DB tokens, so exclude tokens | |
| 399 // which have already been loaded by the fetcher. | |
| 400 if (!in_memory_tokens->count(kOAuthServices[i]) && | |
| 401 db_tokens.count(kOAuthServices[i])) { | |
| 402 std::string db_token = db_tokens.find(kOAuthServices[i])->second; | |
| 403 if (!db_token.empty()) { | |
| 404 VLOG(1) << "Loading " << kOAuthServices[i] << " OAuth token from DB: " | |
| 405 << db_token; | |
| 406 (*in_memory_tokens)[kOAuthServices[i]] = db_token; | |
| 407 FireTokenAvailableNotification(kOAuthServices[i], db_token); | |
| 408 // Failures are only for network errors. | |
| 409 } | |
| 410 } | |
| 411 } | 433 } |
| 412 | 434 |
| 413 if (oauth_token_.empty() && oauth_secret_.empty()) { | 435 if (oauth_token_.empty() && oauth_secret_.empty()) { |
| 414 // Look for GAIA OAuth1 access token and secret. If we have both, and the | 436 // Look for GAIA OAuth1 access token and secret. If we have both, and the |
| 415 // current crendentials are empty, update the credentials. | 437 // current crendentials are empty, update the credentials. |
| 416 std::string oauth_token; | 438 std::string oauth_token; |
| 417 std::string oauth_secret; | 439 std::string oauth_secret; |
| 418 | 440 |
| 419 if (db_tokens.count(GaiaConstants::kGaiaOAuthToken) > 0) | 441 if (db_tokens.count(GaiaConstants::kGaiaOAuthToken) > 0) |
| 420 oauth_token = db_tokens.find(GaiaConstants::kGaiaOAuthToken)->second; | 442 oauth_token = db_tokens.find(GaiaConstants::kGaiaOAuthToken)->second; |
| 421 | 443 |
| 422 if (db_tokens.count(GaiaConstants::kGaiaOAuthSecret) > 0) | 444 if (db_tokens.count(GaiaConstants::kGaiaOAuthSecret) > 0) |
| 423 oauth_secret = db_tokens.find(GaiaConstants::kGaiaOAuthSecret)->second; | 445 oauth_secret = db_tokens.find(GaiaConstants::kGaiaOAuthSecret)->second; |
| 424 | 446 |
| 425 if (!oauth_token.empty() && !oauth_secret.empty()) { | 447 if (!oauth_token.empty() && !oauth_secret.empty()) { |
| 426 UpdateOAuthCredentials(oauth_token, oauth_secret); | 448 UpdateOAuthCredentials(oauth_token, oauth_secret); |
| 427 } | 449 } |
| 428 } | 450 } |
| 429 } | 451 } |
| 430 | 452 |
| 453 void TokenService::LoadSingleTokenIntoMemory( |
| 454 const std::map<std::string, std::string>& db_tokens, |
| 455 std::map<std::string, std::string>* in_memory_tokens, |
| 456 const std::string& service) { |
| 457 // OnIssueAuthTokenSuccess should come from the same thread. |
| 458 // If a token is already present in the map, it could only have |
| 459 // come from a DB read or from IssueAuthToken. Since we should never |
| 460 // fetch from the DB twice in a browser session, it must be from |
| 461 // OnIssueAuthTokenSuccess, which is a live fetcher. |
| 462 // |
| 463 // Network fetched tokens take priority over DB tokens, so exclude tokens |
| 464 // which have already been loaded by the fetcher. |
| 465 if (!in_memory_tokens->count(service) && db_tokens.count(service)) { |
| 466 std::string db_token = db_tokens.find(service)->second; |
| 467 if (!db_token.empty()) { |
| 468 VLOG(1) << "Loading " << service << " token from DB: " << db_token; |
| 469 (*in_memory_tokens)[service] = db_token; |
| 470 FireTokenAvailableNotification(service, db_token); |
| 471 // Failures are only for network errors. |
| 472 } |
| 473 } |
| 474 } |
| 475 |
| 431 void TokenService::Observe(int type, | 476 void TokenService::Observe(int type, |
| 432 const content::NotificationSource& source, | 477 const content::NotificationSource& source, |
| 433 const content::NotificationDetails& details) { | 478 const content::NotificationDetails& details) { |
| 434 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_UPDATED); | 479 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_UPDATED); |
| 435 TokenAvailableDetails* tok_details = | 480 TokenAvailableDetails* tok_details = |
| 436 content::Details<TokenAvailableDetails>(details).ptr(); | 481 content::Details<TokenAvailableDetails>(details).ptr(); |
| 437 OnIssueAuthTokenSuccess(tok_details->service(), tok_details->token()); | 482 OnIssueAuthTokenSuccess(tok_details->service(), tok_details->token()); |
| 438 } | 483 } |
| OLD | NEW |