Home | History | Annotate | Download | only in policy
      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 
     25 namespace policy {
     26 
     27 namespace em = enterprise_management;
     28 
     29 // Responsible for managing the on-disk token cache.
     30 class 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 
     56 UserPolicyIdentityStrategy::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 
     62 void 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 
     70 void 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 
     83 void 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 
    107 void 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 
    115 void 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 
    133 UserPolicyIdentityStrategy::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 
    158 UserPolicyIdentityStrategy::~UserPolicyIdentityStrategy() {}
    159 
    160 std::string UserPolicyIdentityStrategy::GetDeviceToken() {
    161   return device_token_;
    162 }
    163 
    164 std::string UserPolicyIdentityStrategy::GetDeviceID() {
    165   return device_id_;
    166 }
    167 
    168 std::string UserPolicyIdentityStrategy::GetMachineID() {
    169   return std::string();
    170 }
    171 
    172 std::string UserPolicyIdentityStrategy::GetMachineModel() {
    173   return std::string();
    174 }
    175 
    176 em::DeviceRegisterRequest_Type
    177 UserPolicyIdentityStrategy::GetPolicyRegisterType() {
    178   return em::DeviceRegisterRequest::USER;
    179 }
    180 
    181 std::string UserPolicyIdentityStrategy::GetPolicyType() {
    182   return kChromeUserPolicyType;
    183 }
    184 
    185 bool 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 
    194 void 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 
    202 std::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 
    212 void 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 
    223 void 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 
    234 void 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