user_policy_identity_strategy.cc revision dc0f95d653279beabeb9817299e2902918ba123e
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 "chrome/common/notification_details.h"
17#include "chrome/common/notification_service.h"
18#include "chrome/common/notification_source.h"
19#include "content/browser/browser_thread.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 "";
170}
171
172em::DeviceRegisterRequest_Type
173UserPolicyIdentityStrategy::GetPolicyRegisterType() {
174  return em::DeviceRegisterRequest::USER;
175}
176
177std::string UserPolicyIdentityStrategy::GetPolicyType() {
178  return kChromeUserPolicyType;
179}
180
181
182bool UserPolicyIdentityStrategy::GetCredentials(std::string* username,
183                                                std::string* auth_token) {
184  *username = GetCurrentUser();
185  *auth_token = profile_->GetTokenService()->GetTokenForService(
186      GaiaConstants::kDeviceManagementService);
187
188  return !username->empty() && !auth_token->empty() && !device_id_.empty();
189}
190
191void UserPolicyIdentityStrategy::OnDeviceTokenAvailable(
192    const std::string& token) {
193  DCHECK(!device_id_.empty());
194  device_token_ = token;
195  cache_->Store(device_token_, device_id_);
196  NotifyDeviceTokenChanged();
197}
198
199std::string UserPolicyIdentityStrategy::GetCurrentUser() {
200#if defined(OS_CHROMEOS)
201  // TODO(mnissler) On CrOS it seems impossible to figure out what user belongs
202  // to a profile. Revisit after multi-profile support landed.
203  return chromeos::UserManager::Get()->logged_in_user().email();
204#else
205  return profile_->GetBrowserSignin()->GetSignedInUsername();
206#endif
207}
208
209void UserPolicyIdentityStrategy::CheckAndTriggerFetch() {
210  if (!GetCurrentUser().empty() &&
211      profile_->GetTokenService()->HasTokenForService(
212          GaiaConstants::kDeviceManagementService)) {
213    // For user tokens, there is no actual identifier. We generate a random
214    // identifier instead each time we ask for the token.
215    device_id_ = guid::GenerateGUID();
216    NotifyAuthChanged();
217  }
218}
219
220void UserPolicyIdentityStrategy::OnCacheLoaded(const std::string& token,
221                                               const std::string& device_id) {
222  if (!token.empty() && !device_id.empty()) {
223    device_token_ = token;
224    device_id_ = device_id;
225    NotifyDeviceTokenChanged();
226  } else {
227    CheckAndTriggerFetch();
228  }
229}
230
231void UserPolicyIdentityStrategy::Observe(NotificationType type,
232                                         const NotificationSource& source,
233                                         const NotificationDetails& details) {
234  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
235  if (type == NotificationType::TOKEN_AVAILABLE) {
236    if (Source<TokenService>(source).ptr() == profile_->GetTokenService()) {
237      const TokenService::TokenAvailableDetails* token_details =
238          Details<const TokenService::TokenAvailableDetails>(details).ptr();
239      if (token_details->service() == GaiaConstants::kDeviceManagementService)
240        if (device_token_.empty()) {
241          // Request a new device management server token, but only in case we
242          // don't already have it.
243          CheckAndTriggerFetch();
244        }
245    }
246#if defined(OS_CHROMEOS)
247  } else if (type == NotificationType::LOGIN_USER_CHANGED) {
248    CheckAndTriggerFetch();
249#else
250  } else if (type == NotificationType::GOOGLE_SIGNIN_SUCCESSFUL) {
251    if (profile_ == Source<Profile>(source).ptr())
252      CheckAndTriggerFetch();
253#endif
254  } else {
255    NOTREACHED();
256  }
257}
258
259}  // namespace policy
260