1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/signin/mutable_profile_oauth2_token_service.h"
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/webdata/token_web_data.h"
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/webdata/common/web_data_service_base.h"
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(ENABLE_MANAGED_USERS)
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/managed_mode/managed_user_constants.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const char kAccountIdPrefix[] = "AccountId-";
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const size_t kAccountIdPrefixLength = 10;
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool IsLegacyRefreshTokenId(const std::string& service_id) {
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return service_id == GaiaConstants::kGaiaOAuth2LoginRefreshToken;
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool IsLegacyServiceId(const std::string& account_id) {
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return account_id.compare(0u, kAccountIdPrefixLength, kAccountIdPrefix) != 0;
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::string RemoveAccountIdPrefix(const std::string& prefixed_account_id) {
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return prefixed_account_id.substr(kAccountIdPrefixLength);
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)MutableProfileOAuth2TokenService::MutableProfileOAuth2TokenService()
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : web_data_service_request_(0)  {
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)MutableProfileOAuth2TokenService::~MutableProfileOAuth2TokenService() {
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void MutableProfileOAuth2TokenService::Shutdown() {
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (web_data_service_request_ != 0) {
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    scoped_refptr<TokenWebData> token_web_data =
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        TokenWebData::FromBrowserContext(profile());
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DCHECK(token_web_data.get());
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    token_web_data->CancelRequest(web_data_service_request_);
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    web_data_service_request_  = 0;
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ProfileOAuth2TokenService::Shutdown();
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void MutableProfileOAuth2TokenService::LoadCredentials() {
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK_EQ(0, web_data_service_request_);
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CancelAllRequests();
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  refresh_tokens().clear();
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_refptr<TokenWebData> token_web_data =
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      TokenWebData::FromBrowserContext(profile());
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (token_web_data.get())
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    web_data_service_request_ = token_web_data->GetAllTokens(this);
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void MutableProfileOAuth2TokenService::OnWebDataServiceRequestDone(
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    WebDataServiceBase::Handle handle,
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const WDTypedResult* result) {
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK_EQ(web_data_service_request_, handle);
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  web_data_service_request_ = 0;
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (result) {
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DCHECK(result->GetType() == TOKEN_RESULT);
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const WDResult<std::map<std::string, std::string> > * token_result =
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        static_cast<const WDResult<std::map<std::string, std::string> > * > (
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            result);
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    LoadAllCredentialsIntoMemory(token_result->GetValue());
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::string account_id = GetPrimaryAccountId();
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // If |account_id| is not empty, make sure that we have an entry in the
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // map for it.  The entry could be missing if there is a corruption in
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // the token DB while this profile is connected to an account.
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!account_id.empty() && refresh_tokens().count(account_id) == 0) {
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    refresh_tokens()[account_id].reset(
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        new AccountInfo(this, account_id, std::string()));
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // If we don't have a refresh token for the primary account, signal a signin
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // error.
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!account_id.empty() && !RefreshTokenIsAvailable(account_id)) {
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    UpdateAuthError(
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        account_id,
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        GoogleServiceAuthError(
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void MutableProfileOAuth2TokenService::LoadAllCredentialsIntoMemory(
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const std::map<std::string, std::string>& db_tokens) {
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::string old_login_token;
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (std::map<std::string, std::string>::const_iterator iter =
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)           db_tokens.begin();
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)       iter != db_tokens.end();
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)       ++iter) {
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    std::string prefixed_account_id = iter->first;
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    std::string refresh_token = iter->second;
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IsLegacyRefreshTokenId(prefixed_account_id) && !refresh_token.empty())
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      old_login_token = refresh_token;
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IsLegacyServiceId(prefixed_account_id)) {
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      scoped_refptr<TokenWebData> token_web_data =
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          TokenWebData::FromBrowserContext(profile());
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (token_web_data.get())
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        token_web_data->RemoveTokenForService(prefixed_account_id);
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else {
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      DCHECK(!refresh_token.empty());
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      std::string account_id = RemoveAccountIdPrefix(prefixed_account_id);
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      refresh_tokens()[account_id].reset(
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          new AccountInfo(this, account_id, refresh_token));
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      FireRefreshTokenAvailable(account_id);
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // TODO(fgorski): Notify diagnostic observers.
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!old_login_token.empty()) {
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    std::string account_id = GetAccountIdForMigratingRefreshToken();
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (refresh_tokens().count(account_id) == 0)
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      UpdateCredentials(account_id, old_login_token);
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  FireRefreshTokensLoaded();
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::string
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)MutableProfileOAuth2TokenService::GetAccountIdForMigratingRefreshToken() {
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(ENABLE_MANAGED_USERS)
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // TODO(bauerb): Make sure that only services that can deal with supervised
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // users see the supervised user token.
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (profile()->IsManaged())
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return managed_users::kManagedUserPseudoEmail;
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return GetPrimaryAccountId();
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
148