device_token_fetcher.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 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 "chrome/browser/net/gaia/token_service.h"
11#include "chrome/browser/policy/mock_device_management_backend.h"
12#include "chrome/common/chrome_paths.h"
13#include "chrome/common/net/gaia/gaia_constants.h"
14#include "chrome/common/notification_details.h"
15#include "chrome/common/notification_service.h"
16#include "chrome/common/notification_source.h"
17#include "chrome/common/notification_type.h"
18
19namespace {
20
21static const char kPlaceholderDeviceID[] = "placeholder_device_id";
22
23}  // namespace
24
25namespace policy {
26
27bool UserDirDeviceTokenPathProvider::GetPath(FilePath* path) const {
28  FilePath dir_path;
29  if ( PathService::Get(chrome::DIR_USER_DATA, &dir_path))
30    return false;
31  *path = dir_path.Append(FILE_PATH_LITERAL("DeviceManagementToken"));
32  return true;
33}
34
35DeviceTokenFetcher::DeviceTokenFetcher(
36    DeviceManagementBackend* backend,
37    StoredDeviceTokenPathProvider* path_provider)
38    : backend_(backend),
39      path_provider_(path_provider),
40      state_(kStateLoadDeviceTokenFromDisk),
41      device_token_load_complete_event_(true, false) {
42}
43
44void DeviceTokenFetcher::Observe(NotificationType type,
45                                 const NotificationSource& source,
46                                 const NotificationDetails& details) {
47  DCHECK(CalledOnValidThread());
48  if (type == NotificationType::TOKEN_AVAILABLE) {
49    const Source<TokenService> token_service(source);
50    const TokenService::TokenAvailableDetails* token_details =
51        Details<const TokenService::TokenAvailableDetails>(details).ptr();
52    if (token_details->service() == GaiaConstants::kDeviceManagementService &&
53        state_ < kStateHasAuthToken) {
54      DCHECK_EQ(kStateFetchingAuthToken, state_);
55      SetState(kStateHasAuthToken);
56      em::DeviceRegisterRequest register_request;
57      backend_->ProcessRegisterRequest(token_details->token(),
58                                       GetDeviceID(),
59                                       register_request,
60                                       this);
61    }
62  } else {
63    NOTREACHED();
64  }
65}
66
67void DeviceTokenFetcher::HandleRegisterResponse(
68    const em::DeviceRegisterResponse& response) {
69  DCHECK(CalledOnValidThread());
70  DCHECK_EQ(kStateHasAuthToken, state_);
71  if (response.has_device_management_token()) {
72    device_token_ = response.device_management_token();
73    FilePath device_token_path;
74    if (path_provider_->GetPath(&device_token_path)) {
75      BrowserThread::PostTask(
76          BrowserThread::FILE,
77          FROM_HERE,
78          NewRunnableFunction(&WriteDeviceTokenToDisk,
79                              device_token_path,
80                              device_token_));
81    }
82    SetState(kStateHasDeviceToken);
83  } else {
84    NOTREACHED();
85    SetState(kStateFailure);
86  }
87}
88
89void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) {
90  DCHECK(CalledOnValidThread());
91  SetState(kStateFailure);
92}
93
94void DeviceTokenFetcher::StartFetching() {
95  DCHECK(CalledOnValidThread());
96  if (state_ < kStateHasDeviceToken) {
97    FilePath device_token_path;
98    FetcherState new_state = kStateFailure;
99    if (path_provider_->GetPath(&device_token_path)) {
100      if (file_util::PathExists(device_token_path)) {
101        std::string device_token;
102        if (file_util::ReadFileToString(device_token_path, &device_token_)) {
103          new_state = kStateHasDeviceToken;
104        }
105      }
106      if (new_state != kStateHasDeviceToken) {
107        new_state = kStateFetchingAuthToken;
108        // The policy provider gets initialized with the PrefService and Profile
109        // before ServiceTokens are available. Install a notification observer
110        // to ensure that the device management token gets fetched after the
111        // AuthTokens are available if it's needed.
112        registrar_.Add(this,
113                       NotificationType::TOKEN_AVAILABLE,
114                       NotificationService::AllSources());
115      }
116    }
117    SetState(new_state);
118  }
119}
120
121bool DeviceTokenFetcher::IsTokenPending() {
122  DCHECK(CalledOnValidThread());
123  return !device_token_load_complete_event_.IsSignaled();
124}
125
126std::string DeviceTokenFetcher::GetDeviceToken() {
127  DCHECK(CalledOnValidThread());
128  device_token_load_complete_event_.Wait();
129  return device_token_;
130}
131
132void DeviceTokenFetcher::SetState(FetcherState state) {
133  DCHECK(CalledOnValidThread());
134  state_ = state;
135  if (state == kStateFailure) {
136    device_token_load_complete_event_.Signal();
137  } else if (state == kStateHasDeviceToken) {
138    device_token_load_complete_event_.Signal();
139    NotificationService::current()->Notify(
140        NotificationType::DEVICE_TOKEN_AVAILABLE,
141        Source<DeviceTokenFetcher>(this),
142        NotificationService::NoDetails());
143  }
144}
145
146bool DeviceTokenFetcher::IsTokenValid() const {
147  return state_ == kStateHasDeviceToken;
148}
149
150// static
151void DeviceTokenFetcher::WriteDeviceTokenToDisk(
152    const FilePath& path,
153    const std::string& device_token) {
154  file_util::WriteFile(path,
155                       device_token.c_str(),
156                       device_token.length());
157}
158
159// static
160std::string DeviceTokenFetcher::GetDeviceID() {
161  // TODO(danno): fetch a real device_id
162  return kPlaceholderDeviceID;
163}
164
165}
166