• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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