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>;
~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
TokenCache(const base::WeakPtr<UserPolicyIdentityStrategy> & identity_strategy,const FilePath & cache_file)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
Load()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
Store(const std::string & token,const std::string & device_id)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
LoadOnFileThread()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
NotifyOnUIThread(const std::string & token,const std::string & device_id)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
StoreOnFileThread(const std::string & token,const std::string & device_id)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
UserPolicyIdentityStrategy(Profile * profile,const FilePath & cache_file)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
~UserPolicyIdentityStrategy()158 UserPolicyIdentityStrategy::~UserPolicyIdentityStrategy() {}
159
GetDeviceToken()160 std::string UserPolicyIdentityStrategy::GetDeviceToken() {
161 return device_token_;
162 }
163
GetDeviceID()164 std::string UserPolicyIdentityStrategy::GetDeviceID() {
165 return device_id_;
166 }
167
GetMachineID()168 std::string UserPolicyIdentityStrategy::GetMachineID() {
169 return std::string();
170 }
171
GetMachineModel()172 std::string UserPolicyIdentityStrategy::GetMachineModel() {
173 return std::string();
174 }
175
176 em::DeviceRegisterRequest_Type
GetPolicyRegisterType()177 UserPolicyIdentityStrategy::GetPolicyRegisterType() {
178 return em::DeviceRegisterRequest::USER;
179 }
180
GetPolicyType()181 std::string UserPolicyIdentityStrategy::GetPolicyType() {
182 return kChromeUserPolicyType;
183 }
184
GetCredentials(std::string * username,std::string * auth_token)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
OnDeviceTokenAvailable(const std::string & token)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
GetCurrentUser()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
CheckAndTriggerFetch()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
OnCacheLoaded(const std::string & token,const std::string & device_id)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
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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