1// Copyright (c) 2012 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 5login.createScreen('OAuthEnrollmentScreen', 'oauth-enrollment', function() { 6 /** @const */ var STEP_SIGNIN = 'signin'; 7 /** @const */ var STEP_WORKING = 'working'; 8 /** @const */ var STEP_ERROR = 'error'; 9 /** @const */ var STEP_EXPLAIN = 'explain'; 10 /** @const */ var STEP_SUCCESS = 'success'; 11 12 /** @const */ var HELP_TOPIC_ENROLLMENT = 4631259; 13 14 return { 15 EXTERNAL_API: [ 16 'showStep', 17 'showError', 18 'showWorking', 19 'setAuthenticatedUserEmail', 20 'doReload', 21 ], 22 23 /** 24 * URL to load in the sign in frame. 25 */ 26 signInUrl_: null, 27 28 /** 29 * Dialog to confirm that auto-enrollment should really be cancelled. 30 * This is only created the first time it's used. 31 */ 32 confirmDialog_: null, 33 34 /** 35 * The current step. This is the last value passed to showStep(). 36 */ 37 currentStep_: null, 38 39 /** 40 * Opaque token used to correlate request and response while retrieving the 41 * authenticated user's e-mail address from GAIA. 42 */ 43 attemptToken_: null, 44 45 /** @override */ 46 decorate: function() { 47 window.addEventListener('message', 48 this.onMessage_.bind(this), false); 49 $('oauth-enroll-error-retry').addEventListener('click', 50 this.doRetry_.bind(this)); 51 $('oauth-enroll-learn-more-link').addEventListener( 52 'click', 53 function() { 54 chrome.send('launchHelpApp', [HELP_TOPIC_ENROLLMENT]); 55 }); 56 var links = document.querySelectorAll('.oauth-enroll-explain-link'); 57 for (var i = 0; i < links.length; i++) { 58 links[i].addEventListener('click', 59 this.showStep.bind(this, STEP_EXPLAIN)); 60 } 61 62 this.updateLocalizedContent(); 63 }, 64 65 /** 66 * Updates localized strings. 67 */ 68 updateLocalizedContent: function() { 69 $('oauth-enroll-re-enrollment-text').innerHTML = 70 loadTimeData.getStringF( 71 'oauthEnrollReEnrollmentText', 72 '<b id="oauth-enroll-management-domain"></b>'); 73 $('oauth-enroll-management-domain').textContent = this.managementDomain_; 74 $('oauth-enroll-re-enrollment-text').hidden = !this.managementDomain_; 75 }, 76 77 /** 78 * Header text of the screen. 79 * @type {string} 80 */ 81 get header() { 82 return loadTimeData.getString('oauthEnrollScreenTitle'); 83 }, 84 85 /** 86 * Buttons in oobe wizard's button strip. 87 * @type {array} Array of Buttons. 88 */ 89 get buttons() { 90 var buttons = []; 91 var ownerDocument = this.ownerDocument; 92 93 function makeButton(id, classes, label, handler) { 94 var button = ownerDocument.createElement('button'); 95 button.id = id; 96 button.classList.add('oauth-enroll-button'); 97 button.classList.add.apply(button.classList, classes); 98 button.textContent = label; 99 button.addEventListener('click', handler); 100 buttons.push(button); 101 } 102 103 makeButton( 104 'oauth-enroll-cancel-button', 105 ['oauth-enroll-focus-on-error'], 106 loadTimeData.getString('oauthEnrollCancel'), 107 function() { 108 chrome.send('oauthEnrollClose', ['cancel']); 109 }); 110 111 makeButton( 112 'oauth-enroll-back-button', 113 ['oauth-enroll-focus-on-error'], 114 loadTimeData.getString('oauthEnrollCancelAutoEnrollmentGoBack'), 115 function() { 116 chrome.send('oauthEnrollClose', ['cancel']); 117 }); 118 119 makeButton( 120 'oauth-enroll-retry-button', 121 ['oauth-enroll-focus-on-error'], 122 loadTimeData.getString('oauthEnrollRetry'), 123 this.doRetry_.bind(this)); 124 125 makeButton( 126 'oauth-enroll-explain-retry-button', 127 ['oauth-enroll-focus-on-explain'], 128 loadTimeData.getString('oauthEnrollExplainButton'), 129 this.doRetry_.bind(this)); 130 131 makeButton( 132 'oauth-enroll-done-button', 133 ['oauth-enroll-focus-on-success'], 134 loadTimeData.getString('oauthEnrollDone'), 135 function() { 136 chrome.send('oauthEnrollClose', ['done']); 137 }); 138 139 return buttons; 140 }, 141 142 /** 143 * Event handler that is invoked just before the frame is shown. 144 * @param {Object} data Screen init payload, contains the signin frame 145 * URL. 146 */ 147 onBeforeShow: function(data) { 148 var url = data.signin_url; 149 url += '?gaiaUrl=' + encodeURIComponent(data.gaiaUrl); 150 this.signInUrl_ = url; 151 var modes = ['manual', 'forced', 'auto']; 152 for (var i = 0; i < modes.length; ++i) { 153 this.classList.toggle('mode-' + modes[i], 154 data.enrollment_mode == modes[i]); 155 } 156 this.managementDomain_ = data.management_domain; 157 $('oauth-enroll-signin-frame').contentWindow.location.href = 158 this.signInUrl_; 159 this.updateLocalizedContent(); 160 this.showStep(STEP_SIGNIN); 161 }, 162 163 /** 164 * Cancels enrollment and drops the user back to the login screen. 165 */ 166 cancel: function() { 167 chrome.send('oauthEnrollClose', ['cancel']); 168 }, 169 170 /** 171 * Switches between the different steps in the enrollment flow. 172 * @param {string} step the steps to show, one of "signin", "working", 173 * "error", "success". 174 */ 175 showStep: function(step) { 176 this.classList.toggle('oauth-enroll-state-' + this.currentStep_, false); 177 this.classList.toggle('oauth-enroll-state-' + step, true); 178 var focusElements = 179 this.querySelectorAll('.oauth-enroll-focus-on-' + step); 180 for (var i = 0; i < focusElements.length; ++i) { 181 if (getComputedStyle(focusElements[i])['display'] != 'none') { 182 focusElements[i].focus(); 183 break; 184 } 185 } 186 this.currentStep_ = step; 187 }, 188 189 /** 190 * Sets an error message and switches to the error screen. 191 * @param {string} message the error message. 192 * @param {boolean} retry whether the retry link should be shown. 193 */ 194 showError: function(message, retry) { 195 $('oauth-enroll-error-message').textContent = message; 196 $('oauth-enroll-error-retry').hidden = !retry; 197 this.showStep(STEP_ERROR); 198 }, 199 200 /** 201 * Sets a progress message and switches to the working screen. 202 * @param {string} message the progress message. 203 */ 204 showWorking: function(message) { 205 $('oauth-enroll-working-message').textContent = message; 206 this.showStep(STEP_WORKING); 207 }, 208 209 /** 210 * Invoked when the authenticated user's e-mail address has been retrieved. 211 * This completes SAML authentication. 212 * @param {number} attemptToken An opaque token used to correlate this 213 * method invocation with the corresponding request to retrieve the 214 * user's e-mail address. 215 * @param {string} email The authenticated user's e-mail address. 216 */ 217 setAuthenticatedUserEmail: function(attemptToken, email) { 218 if (this.attemptToken_ != attemptToken) 219 return; 220 221 if (!email) 222 this.showError(loadTimeData.getString('fatalEnrollmentError'), false); 223 else 224 chrome.send('oauthEnrollCompleteLogin', [email]); 225 }, 226 227 doReload: function() { 228 $('oauth-enroll-signin-frame').contentWindow.location.href = 229 this.signInUrl_; 230 }, 231 232 /** 233 * Handler for cancellations of an enforced auto-enrollment. 234 */ 235 cancelAutoEnrollment: function() { 236 // Only to be activated for the explain step in auto-enrollment. 237 if (this.currentStep_ !== STEP_EXPLAIN) 238 return; 239 240 if (!this.confirmDialog_) { 241 this.confirmDialog_ = new cr.ui.dialogs.ConfirmDialog(document.body); 242 this.confirmDialog_.setOkLabel( 243 loadTimeData.getString('oauthEnrollCancelAutoEnrollmentConfirm')); 244 this.confirmDialog_.setCancelLabel( 245 loadTimeData.getString('oauthEnrollCancelAutoEnrollmentGoBack')); 246 this.confirmDialog_.setInitialFocusOnCancel(); 247 } 248 this.confirmDialog_.show( 249 loadTimeData.getString('oauthEnrollCancelAutoEnrollmentReally'), 250 this.onConfirmCancelAutoEnrollment_.bind(this)); 251 }, 252 253 /** 254 * Retries the enrollment process after an error occurred in a previous 255 * attempt. This goes to the C++ side through |chrome| first to clean up the 256 * profile, so that the next attempt is performed with a clean state. 257 */ 258 doRetry_: function() { 259 chrome.send('oauthEnrollRetry'); 260 }, 261 262 /** 263 * Handler for confirmation of cancellation of auto-enrollment. 264 */ 265 onConfirmCancelAutoEnrollment_: function() { 266 chrome.send('oauthEnrollClose', ['autocancel']); 267 }, 268 269 /** 270 * Checks if a given HTML5 message comes from the URL loaded into the signin 271 * frame. 272 * @param {Object} m HTML5 message. 273 * @type {boolean} whether the message comes from the signin frame. 274 */ 275 isSigninMessage_: function(m) { 276 return this.signInUrl_ != null && 277 this.signInUrl_.indexOf(m.origin) == 0 && 278 m.source == $('oauth-enroll-signin-frame').contentWindow; 279 }, 280 281 /** 282 * Event handler for HTML5 messages. 283 * @param {Object} m HTML5 message. 284 */ 285 onMessage_: function(m) { 286 if (!this.isSigninMessage_(m)) 287 return; 288 289 var msg = m.data; 290 291 if (msg.method == 'completeLogin') { 292 // A user has successfully authenticated via regular GAIA. 293 chrome.send('oauthEnrollCompleteLogin', [msg.email]); 294 } 295 296 if (msg.method == 'retrieveAuthenticatedUserEmail') { 297 // A user has successfully authenticated via SAML. However, the user's 298 // identity is not known. Instead of reporting success immediately, 299 // retrieve the user's e-mail address first. 300 this.attemptToken_ = msg.attemptToken; 301 this.showWorking(null); 302 chrome.send('oauthEnrollRetrieveAuthenticatedUserEmail', 303 [msg.attemptToken]); 304 } 305 306 if (msg.method == 'authPageLoaded' && this.currentStep_ == STEP_SIGNIN) { 307 if (msg.isSAML) { 308 $('oauth-saml-notice-message').textContent = loadTimeData.getStringF( 309 'samlNotice', 310 msg.domain); 311 } 312 this.classList.toggle('saml', msg.isSAML); 313 chrome.send('frameLoadingCompleted', [0]); 314 } 315 316 if (msg.method == 'insecureContentBlocked') { 317 this.showError( 318 loadTimeData.getStringF('insecureURLEnrollmentError', msg.url), 319 false); 320 } 321 } 322 }; 323}); 324 325