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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/signin/signin_account_id_helper.h"
6
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/signin/profile_oauth2_token_service.h"
11 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
12 #include "chrome/common/pref_names.h"
13 #include "content/public/browser/notification_service.h"
14 #include "google_apis/gaia/gaia_oauth_client.h"
15
16 // TODO(guohui): this class should be moved to a more generic place for reuse.
17 class SigninAccountIdHelper::AccountIdFetcher
18 : public OAuth2TokenService::Consumer,
19 public gaia::GaiaOAuthClient::Delegate {
20 public:
21 AccountIdFetcher(Profile* profile,
22 SigninAccountIdHelper* signin_account_id_helper);
23 virtual ~AccountIdFetcher();
24
25 // OAuth2TokenService::Consumer implementation.
26 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
27 const std::string& access_token,
28 const base::Time& expiration_time) OVERRIDE;
29 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
30 const GoogleServiceAuthError& error) OVERRIDE;
31
32 // gaia::GaiaOAuthClient::Delegate implementation.
33 virtual void OnGetUserIdResponse(const std::string& gaia_id) OVERRIDE;
34 virtual void OnOAuthError() OVERRIDE;
35 virtual void OnNetworkError(int response_code) OVERRIDE;
36
37 private:
38 void Start();
39
40 Profile* profile_;
41 SigninAccountIdHelper* signin_account_id_helper_;
42
43 scoped_ptr<OAuth2TokenService::Request> login_token_request_;
44 scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
45
46 DISALLOW_COPY_AND_ASSIGN(AccountIdFetcher);
47 };
48
AccountIdFetcher(Profile * profile,SigninAccountIdHelper * signin_account_id_helper)49 SigninAccountIdHelper::AccountIdFetcher::AccountIdFetcher(
50 Profile* profile,
51 SigninAccountIdHelper* signin_account_id_helper)
52 : profile_(profile),
53 signin_account_id_helper_(signin_account_id_helper) {
54 Start();
55 }
56
~AccountIdFetcher()57 SigninAccountIdHelper::AccountIdFetcher::~AccountIdFetcher() {}
58
Start()59 void SigninAccountIdHelper::AccountIdFetcher::Start() {
60 ProfileOAuth2TokenService* service =
61 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
62 OAuth2TokenService::ScopeSet scopes;
63 scopes.insert("https://www.googleapis.com/auth/userinfo.profile");
64 login_token_request_ = service->StartRequest(
65 service->GetPrimaryAccountId(), scopes, this);
66 }
67
OnGetTokenSuccess(const OAuth2TokenService::Request * request,const std::string & access_token,const base::Time & expiration_time)68 void SigninAccountIdHelper::AccountIdFetcher::OnGetTokenSuccess(
69 const OAuth2TokenService::Request* request,
70 const std::string& access_token,
71 const base::Time& expiration_time) {
72 DCHECK_EQ(request, login_token_request_.get());
73
74 gaia_oauth_client_.reset(
75 new gaia::GaiaOAuthClient(profile_->GetRequestContext()));
76
77 const int kMaxGetUserIdRetries = 3;
78 gaia_oauth_client_->GetUserId(access_token, kMaxGetUserIdRetries, this);
79 }
80
OnGetTokenFailure(const OAuth2TokenService::Request * request,const GoogleServiceAuthError & error)81 void SigninAccountIdHelper::AccountIdFetcher::OnGetTokenFailure(
82 const OAuth2TokenService::Request* request,
83 const GoogleServiceAuthError& error) {
84 VLOG(1) << "OnGetTokenFailure: " << error.error_message();
85 DCHECK_EQ(request, login_token_request_.get());
86 signin_account_id_helper_->OnPrimaryAccountIdFetched("");
87 }
88
OnGetUserIdResponse(const std::string & account_id)89 void SigninAccountIdHelper::AccountIdFetcher::OnGetUserIdResponse(
90 const std::string& account_id) {
91 signin_account_id_helper_->OnPrimaryAccountIdFetched(account_id);
92 }
93
OnOAuthError()94 void SigninAccountIdHelper::AccountIdFetcher::OnOAuthError() {
95 VLOG(1) << "OnOAuthError";
96 }
97
OnNetworkError(int response_code)98 void SigninAccountIdHelper::AccountIdFetcher::OnNetworkError(
99 int response_code) {
100 VLOG(1) << "OnNetworkError " << response_code;
101 }
102
SigninAccountIdHelper(Profile * profile)103 SigninAccountIdHelper::SigninAccountIdHelper(Profile* profile)
104 : profile_(profile) {
105 registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
106 content::Source<Profile>(profile_));
107
108 ProfileOAuth2TokenService* token_service =
109 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
110 std::string primary_email = token_service->GetPrimaryAccountId();
111 if (!primary_email.empty() &&
112 token_service->RefreshTokenIsAvailable(primary_email) &&
113 !disable_for_test_) {
114 id_fetcher_.reset(new AccountIdFetcher(profile_, this));
115 }
116 token_service->AddObserver(this);
117 }
118
~SigninAccountIdHelper()119 SigninAccountIdHelper::~SigninAccountIdHelper() {
120 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
121 RemoveObserver(this);
122 }
123
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)124 void SigninAccountIdHelper::Observe(
125 int type,
126 const content::NotificationSource& source,
127 const content::NotificationDetails& details) {
128 if (type == chrome::NOTIFICATION_GOOGLE_SIGNED_OUT)
129 profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUserAccountId);
130 }
131
OnRefreshTokenAvailable(const std::string & email)132 void SigninAccountIdHelper::OnRefreshTokenAvailable(const std::string& email) {
133 ProfileOAuth2TokenService* service =
134 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
135 if (email == service->GetPrimaryAccountId()) {
136 std::string current_account_id =
137 profile_->GetPrefs()->GetString(prefs::kGoogleServicesUserAccountId);
138 if (current_account_id.empty() && !disable_for_test_) {
139 id_fetcher_.reset(new AccountIdFetcher(profile_, this));
140 }
141 }
142 }
143
OnPrimaryAccountIdFetched(const std::string & account_id)144 void SigninAccountIdHelper::OnPrimaryAccountIdFetched(
145 const std::string& account_id) {
146 if (!account_id.empty()) {
147 profile_->GetPrefs()->SetString(
148 prefs::kGoogleServicesUserAccountId, account_id);
149 }
150 }
151
152 // static
153 bool SigninAccountIdHelper::disable_for_test_ = false;
154
155 // static
SetDisableForTest(bool disable_for_test)156 void SigninAccountIdHelper::SetDisableForTest(bool disable_for_test) {
157 disable_for_test_ = disable_for_test;
158 }
159
160