ExtensionSyncService: listen for relevant changes instead of being explicitly called...
[chromium-blink-merge.git] / chrome / browser / chromeos / login / easy_unlock / bootstrap_user_context_initializer.cc
blob9d66402fec3b6975da2b61d6f9420baebc455ba1
1 // Copyright 2014 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.
5 #include "chrome/browser/chromeos/login/easy_unlock/bootstrap_user_context_initializer.h"
7 #include <vector>
9 #include "base/strings/string_util.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
12 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
13 #include "chrome/browser/chromeos/profiles/profile_helper.h"
14 #include "chrome/browser/signin/easy_unlock_service_signin_chromeos.h"
15 #include "components/user_manager/user_manager.h"
16 #include "crypto/random.h"
17 #include "google_apis/gaia/gaia_constants.h"
18 #include "google_apis/gaia/gaia_urls.h"
20 namespace chromeos {
22 namespace {
24 const int kMaxGaiaRetries = 5;
25 const int kUserKeyByteSize = 16;
27 } // namespace
29 BootstrapUserContextInitializer::CompleteCallback*
30 BootstrapUserContextInitializer::complete_callback_for_testing_ = NULL;
32 // static
33 void BootstrapUserContextInitializer::SetCompleteCallbackForTesting(
34 CompleteCallback* callback) {
35 complete_callback_for_testing_ = callback;
38 BootstrapUserContextInitializer::BootstrapUserContextInitializer()
39 : random_key_used_(false),
40 weak_ptr_factory_(this) {
43 BootstrapUserContextInitializer::~BootstrapUserContextInitializer() {
46 void BootstrapUserContextInitializer::Start(const std::string& auth_code,
47 const CompleteCallback& callback) {
48 DCHECK(!callback.is_null());
49 callback_ = callback;
51 user_context_.SetAuthFlow(UserContext::AUTH_FLOW_EASY_BOOTSTRAP);
52 StartTokenFetch(auth_code);
55 void BootstrapUserContextInitializer::StartTokenFetch(
56 const std::string& auth_code) {
57 DCHECK(!token_fetcher_);
59 gaia::OAuthClientInfo client_info;
60 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
61 client_info.client_id = gaia_urls->oauth2_chrome_client_id();
62 client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
64 token_fetcher_.reset(
65 new gaia::GaiaOAuthClient(g_browser_process->system_request_context()));
66 token_fetcher_->GetTokensFromAuthCode(client_info, auth_code, kMaxGaiaRetries,
67 this);
70 void BootstrapUserContextInitializer::StartCheckExistingKeys() {
71 const std::string& user_id = user_context_.GetUserID();
73 // Use random key for the first time user.
74 if (!user_manager::UserManager::Get()->IsKnownUser(user_id)) {
75 CreateRandomKey();
76 return;
79 EasyUnlockKeyManager* key_manager =
80 UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
81 key_manager->GetDeviceDataList(
82 UserContext(user_id),
83 base::Bind(&BootstrapUserContextInitializer::OnGetEasyUnlockData,
84 weak_ptr_factory_.GetWeakPtr()));
87 void BootstrapUserContextInitializer::OnGetEasyUnlockData(
88 bool success,
89 const EasyUnlockDeviceKeyDataList& data_list) {
90 // Existing user must have Smart lock keys to use bootstrap flow.
91 if (!success || data_list.empty()) {
92 LOG(ERROR) << "Unable to get Easy unlock key data.";
93 Notify(false);
94 return;
97 EasyUnlockService* service =
98 EasyUnlockService::Get(ProfileHelper::GetSigninProfile());
99 service->AddObserver(this);
101 static_cast<EasyUnlockServiceSignin*>(service)
102 ->SetCurrentUser(user_context_.GetUserID());
103 OnScreenlockStateChanged(service->GetScreenlockState());
106 void BootstrapUserContextInitializer::OnEasyUnlockAuthenticated(
107 EasyUnlockAuthAttempt::Type auth_attempt_type,
108 bool success,
109 const std::string& user_id,
110 const std::string& key_secret,
111 const std::string& key_label) {
112 DCHECK_EQ(EasyUnlockAuthAttempt::TYPE_SIGNIN, auth_attempt_type);
113 if (!success || key_secret.empty()) {
114 LOG(ERROR) << "Failed to sign-in using existing Smart lock key.";
115 Notify(false);
116 return;
119 user_context_.SetKey(Key(key_secret));
120 user_context_.GetKey()->SetLabel(key_label);
121 Notify(true);
124 void BootstrapUserContextInitializer::CreateRandomKey() {
125 std::string random_initial_key;
126 crypto::RandBytes(base::WriteInto(&random_initial_key, kUserKeyByteSize + 1),
127 kUserKeyByteSize);
128 user_context_.SetKey(Key(random_initial_key));
129 random_key_used_ = true;
130 Notify(true);
133 void BootstrapUserContextInitializer::Notify(bool success) {
134 if (complete_callback_for_testing_)
135 complete_callback_for_testing_->Run(success, user_context_);
137 if (callback_.is_null())
138 return;
140 callback_.Run(success, user_context_);
143 void BootstrapUserContextInitializer::OnGetTokensResponse(
144 const std::string& refresh_token,
145 const std::string& access_token,
146 int expires_in_seconds) {
147 user_context_.SetRefreshToken(refresh_token);
149 gaia::OAuthClientInfo client_info;
150 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
151 client_info.client_id = gaia_urls->oauth2_chrome_client_id();
152 client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
154 std::vector<std::string> scopes;
155 scopes.push_back(GaiaConstants::kGoogleUserInfoEmail);
156 scopes.push_back(GaiaConstants::kGoogleUserInfoProfile);
158 token_fetcher_->RefreshToken(client_info, refresh_token, scopes,
159 kMaxGaiaRetries, this);
162 void BootstrapUserContextInitializer::OnRefreshTokenResponse(
163 const std::string& access_token,
164 int expires_in_seconds) {
165 token_fetcher_->GetUserInfo(access_token, kMaxGaiaRetries, this);
168 void BootstrapUserContextInitializer::OnGetUserInfoResponse(
169 scoped_ptr<base::DictionaryValue> user_info) {
170 std::string email;
171 std::string gaia_id;
172 if (!user_info->GetString("email", &email) ||
173 !user_info->GetString("id", &gaia_id)) {
174 LOG(ERROR) << "Bad user info.";
175 Notify(false);
176 return;
179 user_context_.SetUserID(email);
180 user_context_.SetGaiaID(gaia_id);
181 StartCheckExistingKeys();
184 void BootstrapUserContextInitializer::OnOAuthError() {
185 LOG(ERROR) << "Auth error.";
186 Notify(false);
189 void BootstrapUserContextInitializer::OnNetworkError(int response_code) {
190 LOG(ERROR) << "Network error.";
191 Notify(false);
194 void BootstrapUserContextInitializer::OnScreenlockStateChanged(
195 proximity_auth::ScreenlockState state) {
196 // TODO(xiyuan): Add timeout and hook up with error UI after
197 // http://crbug.com/471067.
198 if (state != proximity_auth::ScreenlockState::AUTHENTICATED)
199 return;
201 EasyUnlockService* service =
202 EasyUnlockService::Get(ProfileHelper::GetSigninProfile());
203 service->RemoveObserver(this);
205 service->AttemptAuth(
206 user_context_.GetUserID(),
207 base::Bind(&BootstrapUserContextInitializer::OnEasyUnlockAuthenticated,
208 weak_ptr_factory_.GetWeakPtr()));
211 } // namespace chromeos