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/user_policy_identity_strategy.h" 6 7#include "base/file_util.h" 8#include "chrome/browser/browser_signin.h" 9#include "chrome/browser/net/gaia/token_service.h" 10#include "chrome/browser/policy/proto/device_management_backend.pb.h" 11#include "chrome/browser/policy/proto/device_management_constants.h" 12#include "chrome/browser/policy/proto/device_management_local.pb.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/common/guid.h" 15#include "chrome/common/net/gaia/gaia_constants.h" 16#include "content/browser/browser_thread.h" 17#include "content/common/notification_details.h" 18#include "content/common/notification_service.h" 19#include "content/common/notification_source.h" 20 21#if defined(OS_CHROMEOS) 22#include "chrome/browser/chromeos/login/user_manager.h" 23#endif 24 25namespace policy { 26 27namespace em = enterprise_management; 28 29// Responsible for managing the on-disk token cache. 30class UserPolicyIdentityStrategy::TokenCache 31 : public base::RefCountedThreadSafe< 32 UserPolicyIdentityStrategy::TokenCache> { 33 public: 34 TokenCache(const base::WeakPtr<UserPolicyIdentityStrategy>& identity_strategy, 35 const FilePath& cache_file); 36 37 void Load(); 38 void Store(const std::string& token, const std::string& device_id); 39 40 private: 41 friend class base::RefCountedThreadSafe< 42 UserPolicyIdentityStrategy::TokenCache>; 43 ~TokenCache() {} 44 void LoadOnFileThread(); 45 void NotifyOnUIThread(const std::string& token, 46 const std::string& device_id); 47 void StoreOnFileThread(const std::string& token, 48 const std::string& device_id); 49 50 const base::WeakPtr<UserPolicyIdentityStrategy> identity_strategy_; 51 const FilePath cache_file_; 52 53 DISALLOW_COPY_AND_ASSIGN(TokenCache); 54}; 55 56UserPolicyIdentityStrategy::TokenCache::TokenCache( 57 const base::WeakPtr<UserPolicyIdentityStrategy>& identity_strategy, 58 const FilePath& cache_file) 59 : identity_strategy_(identity_strategy), 60 cache_file_(cache_file) {} 61 62void UserPolicyIdentityStrategy::TokenCache::Load() { 63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 64 BrowserThread::PostTask( 65 BrowserThread::FILE, FROM_HERE, 66 NewRunnableMethod( 67 this, &UserPolicyIdentityStrategy::TokenCache::LoadOnFileThread)); 68} 69 70void UserPolicyIdentityStrategy::TokenCache::Store( 71 const std::string& token, 72 const std::string& device_id) { 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 74 BrowserThread::PostTask( 75 BrowserThread::FILE, FROM_HERE, 76 NewRunnableMethod( 77 this, 78 &UserPolicyIdentityStrategy::TokenCache::StoreOnFileThread, 79 token, 80 device_id)); 81} 82 83void UserPolicyIdentityStrategy::TokenCache::LoadOnFileThread() { 84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 85 std::string device_token; 86 std::string device_id; 87 88 if (file_util::PathExists(cache_file_)) { 89 std::string data; 90 em::DeviceCredentials device_credentials; 91 if (file_util::ReadFileToString(cache_file_, &data) && 92 device_credentials.ParseFromArray(data.c_str(), data.size())) { 93 device_token = device_credentials.device_token(); 94 device_id = device_credentials.device_id(); 95 } 96 } 97 98 BrowserThread::PostTask( 99 BrowserThread::UI, FROM_HERE, 100 NewRunnableMethod( 101 this, 102 &UserPolicyIdentityStrategy::TokenCache::NotifyOnUIThread, 103 device_token, 104 device_id)); 105} 106 107void UserPolicyIdentityStrategy::TokenCache::NotifyOnUIThread( 108 const std::string& token, 109 const std::string& device_id) { 110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 111 if (identity_strategy_.get()) 112 identity_strategy_->OnCacheLoaded(token, device_id); 113} 114 115void UserPolicyIdentityStrategy::TokenCache::StoreOnFileThread( 116 const std::string& token, 117 const std::string& device_id) { 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 119 em::DeviceCredentials device_credentials; 120 device_credentials.set_device_token(token); 121 device_credentials.set_device_id(device_id); 122 std::string data; 123 bool success = device_credentials.SerializeToString(&data); 124 if (!success) { 125 LOG(WARNING) << "Failed serialize device token data, will not write " 126 << cache_file_.value(); 127 return; 128 } 129 130 file_util::WriteFile(cache_file_, data.c_str(), data.length()); 131} 132 133UserPolicyIdentityStrategy::UserPolicyIdentityStrategy( 134 Profile* profile, 135 const FilePath& cache_file) 136 : profile_(profile), 137 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { 138 cache_ = new TokenCache(weak_ptr_factory_.GetWeakPtr(), cache_file); 139 registrar_.Add(this, 140 NotificationType::TOKEN_AVAILABLE, 141 Source<TokenService>(profile->GetTokenService())); 142 143 // Register for the event of user login. The device management token won't 144 // be fetched until we know the domain of the currently logged in user. 145#if defined(OS_CHROMEOS) 146 registrar_.Add(this, 147 NotificationType::LOGIN_USER_CHANGED, 148 NotificationService::AllSources()); 149#else 150 registrar_.Add(this, 151 NotificationType::GOOGLE_SIGNIN_SUCCESSFUL, 152 Source<Profile>(profile_)); 153#endif 154 155 cache_->Load(); 156} 157 158UserPolicyIdentityStrategy::~UserPolicyIdentityStrategy() {} 159 160std::string UserPolicyIdentityStrategy::GetDeviceToken() { 161 return device_token_; 162} 163 164std::string UserPolicyIdentityStrategy::GetDeviceID() { 165 return device_id_; 166} 167 168std::string UserPolicyIdentityStrategy::GetMachineID() { 169 return std::string(); 170} 171 172std::string UserPolicyIdentityStrategy::GetMachineModel() { 173 return std::string(); 174} 175 176em::DeviceRegisterRequest_Type 177UserPolicyIdentityStrategy::GetPolicyRegisterType() { 178 return em::DeviceRegisterRequest::USER; 179} 180 181std::string UserPolicyIdentityStrategy::GetPolicyType() { 182 return kChromeUserPolicyType; 183} 184 185bool UserPolicyIdentityStrategy::GetCredentials(std::string* username, 186 std::string* auth_token) { 187 *username = GetCurrentUser(); 188 *auth_token = profile_->GetTokenService()->GetTokenForService( 189 GaiaConstants::kDeviceManagementService); 190 191 return !username->empty() && !auth_token->empty() && !device_id_.empty(); 192} 193 194void UserPolicyIdentityStrategy::OnDeviceTokenAvailable( 195 const std::string& token) { 196 DCHECK(!device_id_.empty()); 197 device_token_ = token; 198 cache_->Store(device_token_, device_id_); 199 NotifyDeviceTokenChanged(); 200} 201 202std::string UserPolicyIdentityStrategy::GetCurrentUser() { 203#if defined(OS_CHROMEOS) 204 // TODO(mnissler) On CrOS it seems impossible to figure out what user belongs 205 // to a profile. Revisit after multi-profile support landed. 206 return chromeos::UserManager::Get()->logged_in_user().email(); 207#else 208 return profile_->GetBrowserSignin()->GetSignedInUsername(); 209#endif 210} 211 212void UserPolicyIdentityStrategy::CheckAndTriggerFetch() { 213 if (!GetCurrentUser().empty() && 214 profile_->GetTokenService()->HasTokenForService( 215 GaiaConstants::kDeviceManagementService)) { 216 // For user tokens, there is no actual identifier. We generate a random 217 // identifier instead each time we ask for the token. 218 device_id_ = guid::GenerateGUID(); 219 NotifyAuthChanged(); 220 } 221} 222 223void UserPolicyIdentityStrategy::OnCacheLoaded(const std::string& token, 224 const std::string& device_id) { 225 if (!token.empty() && !device_id.empty()) { 226 device_token_ = token; 227 device_id_ = device_id; 228 NotifyDeviceTokenChanged(); 229 } else { 230 CheckAndTriggerFetch(); 231 } 232} 233 234void UserPolicyIdentityStrategy::Observe(NotificationType type, 235 const NotificationSource& source, 236 const NotificationDetails& details) { 237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 238 if (type == NotificationType::TOKEN_AVAILABLE) { 239 if (Source<TokenService>(source).ptr() == profile_->GetTokenService()) { 240 const TokenService::TokenAvailableDetails* token_details = 241 Details<const TokenService::TokenAvailableDetails>(details).ptr(); 242 if (token_details->service() == GaiaConstants::kDeviceManagementService) 243 if (device_token_.empty()) { 244 // Request a new device management server token, but only in case we 245 // don't already have it. 246 CheckAndTriggerFetch(); 247 } 248 } 249#if defined(OS_CHROMEOS) 250 } else if (type == NotificationType::LOGIN_USER_CHANGED) { 251 CheckAndTriggerFetch(); 252#else 253 } else if (type == NotificationType::GOOGLE_SIGNIN_SUCCESSFUL) { 254 if (profile_ == Source<Profile>(source).ptr()) 255 CheckAndTriggerFetch(); 256#endif 257 } else { 258 NOTREACHED(); 259 } 260} 261 262} // namespace policy 263