device_token_fetcher.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
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 3// found in the LICENSE file. 4 5#include "chrome/browser/policy/device_token_fetcher.h" 6 7#include "base/file_util.h" 8#include "base/path_service.h" 9#include "base/singleton.h" 10#include "base/string_util.h" 11#include "chrome/browser/net/gaia/token_service.h" 12#include "chrome/browser/policy/proto/device_management_local.pb.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/common/chrome_paths.h" 15#include "chrome/common/guid.h" 16#include "chrome/common/net/gaia/gaia_constants.h" 17#include "chrome/common/notification_details.h" 18#include "chrome/common/notification_service.h" 19#include "chrome/common/notification_source.h" 20#include "chrome/common/notification_type.h" 21 22#if defined(OS_CHROMEOS) 23#include "chrome/browser/chromeos/login/user_manager.h" 24#else 25#include "chrome/browser/browser_signin.h" 26#endif 27 28namespace { 29 30// Domain names that are known not to be managed. 31// We don't register the device when such a user logs in. 32const char* kNonManagedDomains[] = { 33 "@googlemail.com", 34 "@gmail.com" 35}; 36 37// Checks the domain part of the given username against the list of known 38// non-managed domain names. Returns false if |username| is empty or its 39// in a domain known not to be managed. 40bool CanBeInManagedDomain(const std::string& username) { 41 if (username.empty()) { 42 // This means incognito user in case of ChromiumOS and 43 // no logged-in user in case of Chromium (SigninService). 44 return false; 45 } 46 for (size_t i = 0; i < arraysize(kNonManagedDomains); i++) { 47 if (EndsWith(username, kNonManagedDomains[i], true)) { 48 return false; 49 } 50 } 51 return true; 52} 53 54} // namespace 55 56namespace policy { 57 58namespace em = enterprise_management; 59 60DeviceTokenFetcher::ObserverRegistrar::ObserverRegistrar() {} 61 62DeviceTokenFetcher::ObserverRegistrar::~ObserverRegistrar() { 63 RemoveAll(); 64} 65 66void DeviceTokenFetcher::ObserverRegistrar::Init( 67 DeviceTokenFetcher* token_fetcher) { 68 token_fetcher_ = token_fetcher; 69} 70 71void DeviceTokenFetcher::ObserverRegistrar::AddObserver( 72 DeviceTokenFetcher::Observer* observer) { 73 observers_.push_back(observer); 74 token_fetcher_->AddObserver(observer); 75} 76 77void DeviceTokenFetcher::ObserverRegistrar::RemoveAll() { 78 for (std::vector<DeviceTokenFetcher::Observer*>::iterator it = 79 observers_.begin(); it != observers_.end(); ++it) { 80 token_fetcher_->RemoveObserver(*it); 81 } 82 observers_.clear(); 83} 84 85DeviceTokenFetcher::DeviceTokenFetcher( 86 DeviceManagementBackend* backend, 87 Profile* profile, 88 const FilePath& token_path) 89 : profile_(profile), 90 token_path_(token_path), 91 backend_(backend), 92 state_(kStateNotStarted), 93 device_token_load_complete_event_(true, false) { 94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 95 96 TokenService* token_service = profile_->GetTokenService(); 97 auth_token_ = token_service->GetTokenForService( 98 GaiaConstants::kDeviceManagementService); 99 100 registrar_.Add(this, 101 NotificationType::TOKEN_AVAILABLE, 102 Source<TokenService>(token_service)); 103 // Register for the event of user login. The device management token won't 104 // be fetched until we know the domain of the currently logged in user. 105#if defined(OS_CHROMEOS) 106 registrar_.Add(this, 107 NotificationType::LOGIN_USER_CHANGED, 108 NotificationService::AllSources()); 109#else 110 registrar_.Add(this, 111 NotificationType::GOOGLE_SIGNIN_SUCCESSFUL, 112 Source<Profile>(profile_)); 113#endif 114} 115 116DeviceTokenFetcher::~DeviceTokenFetcher() {} 117 118void DeviceTokenFetcher::Observe(NotificationType type, 119 const NotificationSource& source, 120 const NotificationDetails& details) { 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 122 if (type == NotificationType::TOKEN_AVAILABLE) { 123 if (Source<TokenService>(source).ptr() == profile_->GetTokenService()) { 124 const TokenService::TokenAvailableDetails* token_details = 125 Details<const TokenService::TokenAvailableDetails>(details).ptr(); 126 if (token_details->service() == GaiaConstants::kDeviceManagementService) { 127 if (!HasAuthToken()) { 128 auth_token_ = token_details->token(); 129 SendServerRequestIfPossible(); 130 } 131 } 132 } 133#if defined(OS_CHROMEOS) 134 } else if (type == NotificationType::LOGIN_USER_CHANGED) { 135 SendServerRequestIfPossible(); 136#else 137 } else if (type == NotificationType::GOOGLE_SIGNIN_SUCCESSFUL) { 138 if (profile_ == Source<Profile>(source).ptr()) { 139 SendServerRequestIfPossible(); 140 } 141#endif 142 } else { 143 NOTREACHED(); 144 } 145} 146 147std::string DeviceTokenFetcher::GetCurrentUser() { 148#if defined(OS_CHROMEOS) 149 return chromeos::UserManager::Get()->logged_in_user().email(); 150#else 151 return profile_->GetBrowserSignin()->GetSignedInUsername(); 152#endif 153} 154 155void DeviceTokenFetcher::HandleRegisterResponse( 156 const em::DeviceRegisterResponse& response) { 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 158 DCHECK_EQ(kStateRequestingDeviceTokenFromServer, state_); 159 if (response.has_device_management_token()) { 160 device_token_ = response.device_management_token(); 161 BrowserThread::PostTask( 162 BrowserThread::FILE, 163 FROM_HERE, 164 NewRunnableFunction(&WriteDeviceTokenToDisk, 165 token_path_, 166 device_token_, 167 device_id_)); 168 SetState(kStateHasDeviceToken); 169 } else { 170 NOTREACHED(); 171 SetState(kStateFailure); 172 } 173} 174 175void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) { 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 177 // For privacy reasons, delete all identifying data when this device is not 178 // managed. 179 if (code == DeviceManagementBackend::kErrorServiceManagementNotSupported) { 180 device_token_ = std::string(); 181 device_id_ = std::string(); 182 BrowserThread::PostTask( 183 BrowserThread::FILE, 184 FROM_HERE, 185 // The Windows compiler needs explicit template instantiation. 186 NewRunnableFunction<bool(*)(const FilePath&, bool), FilePath, bool>( 187 &file_util::Delete, token_path_, false)); 188 SetState(kStateNotManaged); 189 return; 190 } 191 SetState(kStateFailure); 192} 193 194void DeviceTokenFetcher::Restart() { 195 DCHECK(!IsTokenPending()); 196 device_token_.clear(); 197 device_token_load_complete_event_.Reset(); 198 MakeReadyToRequestDeviceToken(); 199} 200 201void DeviceTokenFetcher::StartFetching() { 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 203 if (state_ == kStateNotStarted) { 204 SetState(kStateLoadDeviceTokenFromDisk); 205 // The file calls for loading the persisted token must be deferred to the 206 // FILE thread. 207 BrowserThread::PostTask( 208 BrowserThread::FILE, 209 FROM_HERE, 210 NewRunnableMethod(this, 211 &DeviceTokenFetcher::AttemptTokenLoadFromDisk)); 212 } 213} 214 215void DeviceTokenFetcher::AttemptTokenLoadFromDisk() { 216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 217 if (file_util::PathExists(token_path_)) { 218 std::string data; 219 em::DeviceCredentials device_credentials; 220 if (file_util::ReadFileToString(token_path_, &data) && 221 device_credentials.ParseFromArray(data.c_str(), data.size())) { 222 device_token_ = device_credentials.device_token(); 223 device_id_ = device_credentials.device_id(); 224 if (!device_token_.empty() && !device_id_.empty()) { 225 BrowserThread::PostTask( 226 BrowserThread::UI, 227 FROM_HERE, 228 NewRunnableMethod(this, 229 &DeviceTokenFetcher::SetState, 230 kStateHasDeviceToken)); 231 return; 232 } 233 } 234 } 235 236 BrowserThread::PostTask( 237 BrowserThread::UI, 238 FROM_HERE, 239 NewRunnableMethod(this, 240 &DeviceTokenFetcher::MakeReadyToRequestDeviceToken)); 241} 242 243void DeviceTokenFetcher::MakeReadyToRequestDeviceToken() { 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 245 SetState(kStateReadyToRequestDeviceTokenFromServer); 246 SendServerRequestIfPossible(); 247} 248 249void DeviceTokenFetcher::SendServerRequestIfPossible() { 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 251 std::string username = GetCurrentUser(); 252 if (state_ == kStateReadyToRequestDeviceTokenFromServer 253 && HasAuthToken() 254 && backend_ 255 && !username.empty()) { 256 if (CanBeInManagedDomain(username)) { 257 em::DeviceRegisterRequest register_request; 258 SetState(kStateRequestingDeviceTokenFromServer); 259 backend_->ProcessRegisterRequest(auth_token_, 260 GetDeviceID(), 261 register_request, 262 this); 263 } else { 264 SetState(kStateNotManaged); 265 } 266 } 267} 268 269bool DeviceTokenFetcher::IsTokenPending() { 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 271 return !device_token_load_complete_event_.IsSignaled(); 272} 273 274std::string DeviceTokenFetcher::GetDeviceToken() { 275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 276 device_token_load_complete_event_.Wait(); 277 return device_token_; 278} 279 280std::string DeviceTokenFetcher::GetDeviceID() { 281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 282 // As long as access to this is only allowed from the UI thread, no explicit 283 // locking is necessary to prevent the ID from being generated twice. 284 if (device_id_.empty()) 285 device_id_ = GenerateNewDeviceID(); 286 return device_id_; 287} 288 289void DeviceTokenFetcher::SetState(FetcherState state) { 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 291 if (state_ == state) 292 return; 293 state_ = state; 294 if (state == kStateFailure) { 295 device_token_load_complete_event_.Signal(); 296 NotifyTokenError(); 297 } else if (state == kStateNotManaged) { 298 device_token_load_complete_event_.Signal(); 299 NotifyNotManaged(); 300 } else if (state == kStateHasDeviceToken) { 301 device_token_load_complete_event_.Signal(); 302 NotifyTokenSuccess(); 303 } 304} 305 306void DeviceTokenFetcher::GetDeviceTokenPath(FilePath* token_path) const { 307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 308 *token_path = token_path_; 309} 310 311bool DeviceTokenFetcher::IsTokenValid() const { 312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 313 return state_ == kStateHasDeviceToken; 314} 315 316// static 317void DeviceTokenFetcher::WriteDeviceTokenToDisk( 318 const FilePath& path, 319 const std::string& device_token, 320 const std::string& device_id) { 321 em::DeviceCredentials device_credentials; 322 device_credentials.set_device_token(device_token); 323 device_credentials.set_device_id(device_id); 324 std::string data; 325 bool no_error = device_credentials.SerializeToString(&data); 326 DCHECK(no_error); 327 file_util::WriteFile(path, data.c_str(), data.length()); 328} 329 330// static 331std::string DeviceTokenFetcher::GenerateNewDeviceID() { 332 return guid::GenerateGUID(); 333} 334 335} // namespace policy 336