1 // Copyright 2014 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.
5 #include "chrome/browser/chromeos/policy/consumer_enrollment_handler.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/browser_process_platform_part.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18 #include "chrome/browser/chromeos/policy/device_cloud_policy_initializer.h"
19 #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
20 #include "chrome/browser/chromeos/profiles/profile_helper.h"
21 #include "chrome/browser/notifications/notification.h"
22 #include "chrome/browser/notifications/notification_delegate.h"
23 #include "chrome/browser/notifications/notification_ui_manager.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
26 #include "chrome/browser/signin/signin_manager_factory.h"
27 #include "chrome/browser/ui/browser_navigator.h"
28 #include "chrome/common/url_constants.h"
29 #include "components/policy/core/common/cloud/device_management_service.h"
30 #include "components/signin/core/browser/profile_oauth2_token_service.h"
31 #include "components/signin/core/browser/signin_manager_base.h"
32 #include "components/user_manager/user_manager.h"
33 #include "content/public/browser/notification_details.h"
34 #include "content/public/browser/notification_service.h"
35 #include "content/public/browser/notification_source.h"
36 #include "google_apis/gaia/gaia_constants.h"
37 #include "google_apis/gaia/google_service_auth_error.h"
38 #include "grit/generated_resources.h"
39 #include "grit/theme_resources.h"
40 #include "policy/proto/device_management_backend.pb.h"
41 #include "third_party/WebKit/public/web/WebTextDirection.h"
42 #include "ui/base/l10n/l10n_util.h"
43 #include "ui/base/page_transition_types.h"
44 #include "ui/base/resource/resource_bundle.h"
45 #include "ui/base/window_open_disposition.h"
46 #include "ui/message_center/notification.h"
47 #include "ui/message_center/notification_types.h"
48 #include "ui/message_center/notifier_settings.h"
51 namespace em = enterprise_management;
55 // Desktop notification constants.
56 const char kEnrollmentNotificationId[] = "consumer_management.enroll";
57 const char kEnrollmentNotificationUrl[] = "chrome://consumer-management/enroll";
59 // The path to the consumer management enrollment/unenrollment confirmation
60 // overlay, relative to the settings page URL.
61 const char kConsumerManagementOverlay[] = "consumer-management-overlay";
63 // Returns the account ID signed in to |profile|.
64 const std::string& GetAccountIdFromProfile(Profile* profile) {
65 return SigninManagerFactory::GetForProfile(profile)->
66 GetAuthenticatedAccountId();
69 class DesktopNotificationDelegate : public NotificationDelegate {
71 // |button_click_callback| is called when the button in the notification is
73 DesktopNotificationDelegate(const std::string& id,
74 const base::Closure& button_click_callback);
76 // NotificationDelegate:
77 virtual std::string id() const override;
78 virtual void ButtonClick(int button_index) override;
81 virtual ~DesktopNotificationDelegate();
84 base::Closure button_click_callback_;
86 DISALLOW_COPY_AND_ASSIGN(DesktopNotificationDelegate);
89 DesktopNotificationDelegate::DesktopNotificationDelegate(
90 const std::string& id,
91 const base::Closure& button_click_callback)
92 : id_(id), button_click_callback_(button_click_callback) {
95 DesktopNotificationDelegate::~DesktopNotificationDelegate() {
98 std::string DesktopNotificationDelegate::id() const {
102 void DesktopNotificationDelegate::ButtonClick(int button_index) {
103 button_click_callback_.Run();
110 ConsumerEnrollmentHandler::ConsumerEnrollmentHandler(
111 ConsumerManagementService* consumer_management_service,
112 DeviceManagementService* device_management_service)
113 : Consumer("consumer_enrollment_handler"),
114 consumer_management_service_(consumer_management_service),
115 device_management_service_(device_management_service),
116 enrolling_profile_(NULL),
117 weak_ptr_factory_(this) {
119 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
120 content::NotificationService::AllSources());
123 ConsumerEnrollmentHandler::~ConsumerEnrollmentHandler() {
124 if (enrolling_profile_) {
125 ProfileOAuth2TokenServiceFactory::GetForProfile(enrolling_profile_)->
126 RemoveObserver(this);
128 registrar_.Remove(this,
129 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
130 content::NotificationService::AllSources());
133 void ConsumerEnrollmentHandler::Observe(
135 const content::NotificationSource& source,
136 const content::NotificationDetails& details) {
137 if (type != chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED) {
138 NOTREACHED() << "Unexpected notification " << type;
142 Profile* profile = content::Details<Profile>(details).ptr();
143 if (chromeos::ProfileHelper::IsOwnerProfile(profile))
144 OnOwnerSignin(profile);
147 void ConsumerEnrollmentHandler::OnRefreshTokenAvailable(
148 const std::string& account_id) {
149 CHECK(enrolling_profile_);
151 if (account_id == GetAccountIdFromProfile(enrolling_profile_)) {
152 ProfileOAuth2TokenServiceFactory::GetForProfile(enrolling_profile_)->
153 RemoveObserver(this);
154 OnOwnerRefreshTokenAvailable();
158 void ConsumerEnrollmentHandler::OnGetTokenSuccess(
159 const OAuth2TokenService::Request* request,
160 const std::string& access_token,
161 const base::Time& expiration_time) {
162 DCHECK_EQ(token_request_, request);
163 base::MessageLoop::current()->DeleteSoon(FROM_HERE, token_request_.release());
165 OnOwnerAccessTokenAvailable(access_token);
168 void ConsumerEnrollmentHandler::OnGetTokenFailure(
169 const OAuth2TokenService::Request* request,
170 const GoogleServiceAuthError& error) {
171 DCHECK_EQ(token_request_, request);
172 base::MessageLoop::current()->DeleteSoon(FROM_HERE, token_request_.release());
174 LOG(ERROR) << "Failed to get the access token: " << error.ToString();
175 EndEnrollment(ConsumerManagementService::ENROLLMENT_STAGE_GET_TOKEN_FAILED);
178 void ConsumerEnrollmentHandler::OnOwnerSignin(Profile* profile) {
179 const ConsumerManagementService::EnrollmentStage stage =
180 consumer_management_service_->GetEnrollmentStage();
182 case ConsumerManagementService::ENROLLMENT_STAGE_NONE:
186 case ConsumerManagementService::ENROLLMENT_STAGE_OWNER_STORED:
187 // Continue the enrollment process after the owner signs in.
188 ContinueEnrollmentProcess(profile);
191 case ConsumerManagementService::ENROLLMENT_STAGE_SUCCESS:
192 case ConsumerManagementService::ENROLLMENT_STAGE_CANCELED:
193 case ConsumerManagementService::ENROLLMENT_STAGE_BOOT_LOCKBOX_FAILED:
194 case ConsumerManagementService::ENROLLMENT_STAGE_DM_SERVER_FAILED:
195 case ConsumerManagementService::ENROLLMENT_STAGE_GET_TOKEN_FAILED:
196 ShowDesktopNotificationAndResetStage(stage, profile);
199 case ConsumerManagementService::ENROLLMENT_STAGE_REQUESTED:
200 case ConsumerManagementService::ENROLLMENT_STAGE_LAST:
201 NOTREACHED() << "Unexpected enrollment stage " << stage;
206 void ConsumerEnrollmentHandler::ContinueEnrollmentProcess(Profile* profile) {
207 enrolling_profile_ = profile;
209 // First, we need to ensure that the refresh token is available.
210 const std::string& account_id = GetAccountIdFromProfile(profile);
211 ProfileOAuth2TokenService* token_service =
212 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
213 if (token_service->RefreshTokenIsAvailable(account_id)) {
214 OnOwnerRefreshTokenAvailable();
216 token_service->AddObserver(this);
220 void ConsumerEnrollmentHandler::OnOwnerRefreshTokenAvailable() {
221 CHECK(enrolling_profile_);
223 // Now we can request the OAuth access token for device management to send the
224 // device registration request to the device management server.
225 OAuth2TokenService::ScopeSet oauth_scopes;
226 oauth_scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
227 const std::string& account_id = GetAccountIdFromProfile(enrolling_profile_);
228 token_request_ = ProfileOAuth2TokenServiceFactory::GetForProfile(
229 enrolling_profile_)->StartRequest(account_id, oauth_scopes, this);
232 void ConsumerEnrollmentHandler::OnOwnerAccessTokenAvailable(
233 const std::string& access_token) {
234 // Now that we have the access token, we got everything we need to send the
235 // device registration request to the device management server.
236 BrowserPolicyConnectorChromeOS* connector =
237 g_browser_process->platform_part()->browser_policy_connector_chromeos();
238 DeviceCloudPolicyInitializer* initializer =
239 connector->GetDeviceCloudPolicyInitializer();
242 policy::DeviceCloudPolicyInitializer::AllowedDeviceModes device_modes;
243 device_modes[policy::DEVICE_MODE_ENTERPRISE] = true;
245 initializer->StartEnrollment(
246 em::PolicyData::CONSUMER_MANAGED,
247 device_management_service_,
249 false, // is_auto_enrollment
251 base::Bind(&ConsumerEnrollmentHandler::OnEnrollmentCompleted,
252 weak_ptr_factory_.GetWeakPtr()));
255 void ConsumerEnrollmentHandler::OnEnrollmentCompleted(EnrollmentStatus status) {
256 if (status.status() != EnrollmentStatus::STATUS_SUCCESS) {
257 LOG(ERROR) << "Failed to enroll the device."
258 << " status=" << status.status()
259 << " client_status=" << status.client_status()
260 << " http_status=" << status.http_status()
261 << " store_status=" << status.store_status()
262 << " validation_status=" << status.validation_status();
263 EndEnrollment(ConsumerManagementService::ENROLLMENT_STAGE_DM_SERVER_FAILED);
267 EndEnrollment(ConsumerManagementService::ENROLLMENT_STAGE_SUCCESS);
270 void ConsumerEnrollmentHandler::EndEnrollment(
271 ConsumerManagementService::EnrollmentStage stage) {
272 Profile* profile = enrolling_profile_;
273 enrolling_profile_ = NULL;
275 consumer_management_service_->SetEnrollmentStage(stage);
276 if (user_manager::UserManager::Get()->IsCurrentUserOwner())
277 ShowDesktopNotificationAndResetStage(stage, profile);
280 void ConsumerEnrollmentHandler::ShowDesktopNotificationAndResetStage(
281 ConsumerManagementService::EnrollmentStage stage, Profile* profile) {
282 base::string16 title;
284 base::string16 button_label;
285 base::Closure button_click_callback;
287 if (stage == ConsumerManagementService::ENROLLMENT_STAGE_SUCCESS) {
288 title = l10n_util::GetStringUTF16(
289 IDS_CONSUMER_MANAGEMENT_ENROLLMENT_NOTIFICATION_TITLE);
290 body = l10n_util::GetStringUTF16(
291 IDS_CONSUMER_MANAGEMENT_ENROLLMENT_NOTIFICATION_BODY);
292 button_label = l10n_util::GetStringUTF16(
293 IDS_CONSUMER_MANAGEMENT_NOTIFICATION_MODIFY_SETTINGS_BUTTON);
294 button_click_callback = base::Bind(
295 &ConsumerEnrollmentHandler::OpenSettingsPage,
296 weak_ptr_factory_.GetWeakPtr(),
299 title = l10n_util::GetStringUTF16(
300 IDS_CONSUMER_MANAGEMENT_ENROLLMENT_FAILURE_NOTIFICATION_TITLE);
301 body = l10n_util::GetStringUTF16(
302 IDS_CONSUMER_MANAGEMENT_ENROLLMENT_FAILURE_NOTIFICATION_BODY);
303 button_label = l10n_util::GetStringUTF16(
304 IDS_CONSUMER_MANAGEMENT_NOTIFICATION_TRY_AGAIN_BUTTON);
305 button_click_callback = base::Bind(
306 &ConsumerEnrollmentHandler::TryEnrollmentAgain,
307 weak_ptr_factory_.GetWeakPtr(),
311 message_center::RichNotificationData optional_field;
312 optional_field.buttons.push_back(message_center::ButtonInfo(button_label));
313 Notification notification(
314 message_center::NOTIFICATION_TYPE_SIMPLE,
315 GURL(kEnrollmentNotificationUrl),
318 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
319 IDR_CONSUMER_MANAGEMENT_NOTIFICATION_ICON),
320 blink::WebTextDirectionDefault,
321 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
322 kEnrollmentNotificationId),
323 base::string16(), // display_source
324 base::UTF8ToUTF16(kEnrollmentNotificationId),
326 new DesktopNotificationDelegate(kEnrollmentNotificationId,
327 button_click_callback));
328 notification.SetSystemPriority();
329 g_browser_process->notification_ui_manager()->Add(notification, profile);
331 consumer_management_service_->SetEnrollmentStage(
332 ConsumerManagementService::ENROLLMENT_STAGE_NONE);
335 void ConsumerEnrollmentHandler::OpenSettingsPage(Profile* profile) const {
336 const GURL url(chrome::kChromeUISettingsURL);
337 chrome::NavigateParams params(profile, url, ui::PAGE_TRANSITION_LINK);
338 params.disposition = NEW_FOREGROUND_TAB;
339 chrome::Navigate(¶ms);
342 void ConsumerEnrollmentHandler::TryEnrollmentAgain(Profile* profile) const {
343 const GURL base_url(chrome::kChromeUISettingsURL);
344 const GURL url = base_url.Resolve(kConsumerManagementOverlay);
346 chrome::NavigateParams params(profile, url, ui::PAGE_TRANSITION_LINK);
347 params.disposition = NEW_FOREGROUND_TAB;
348 chrome::Navigate(¶ms);
351 } // namespace policy