From b129bf9f4091fae57ee40419ed80343446bfd712 Mon Sep 17 00:00:00 2001
From: Shane Tomlinson <stomlinson@mozilla.com>
Date: Mon, 9 Jan 2012 20:55:02 +0000
Subject: [PATCH] Starting to hook up two level auth in the front end.

* Update network/user to handle two level auth.
* Update tests that check authentication status to check for correct status.
* State machine checks for the correct authentication level for an email address.
---
 .../dialog/controllers/required_email.js      |  1 +
 .../static/dialog/resources/internal_api.js   |  2 +-
 .../static/dialog/resources/state_machine.js  | 23 ++++++++++++--
 .../static/dialog/views/required_email.ejs    |  8 ++++-
 resources/static/shared/network.js            | 12 ++++----
 .../primary_user_provisioned_unit_test.js     |  2 +-
 .../resources/state_machine_unit_test.js      | 30 +++++++++++++++----
 .../test/qunit/shared/user_unit_test.js       |  2 +-
 .../static/test/qunit/testHelpers/helpers.js  |  1 +
 9 files changed, 63 insertions(+), 18 deletions(-)

diff --git a/resources/static/dialog/controllers/required_email.js b/resources/static/dialog/controllers/required_email.js
index 59b4f351d..de8d29496 100644
--- a/resources/static/dialog/controllers/required_email.js
+++ b/resources/static/dialog/controllers/required_email.js
@@ -233,6 +233,7 @@ BrowserID.Modules.RequiredEmail = (function() {
           verify: false,
           signin: false,
           password: false,
+          secondary_auth: false,
           primary: false
         }, options);
         self.renderDialog("required_email", options);
diff --git a/resources/static/dialog/resources/internal_api.js b/resources/static/dialog/resources/internal_api.js
index a019ddf73..c6528aba4 100644
--- a/resources/static/dialog/resources/internal_api.js
+++ b/resources/static/dialog/resources/internal_api.js
@@ -62,7 +62,7 @@
         storage.site.set(origin, "remember", true);
       }
 
-      complete(authenticated || null);
+      complete(!!authenticated || null);
     }, complete.curry(null));
   };
 
diff --git a/resources/static/dialog/resources/state_machine.js b/resources/static/dialog/resources/state_machine.js
index 488c57638..142261ce3 100644
--- a/resources/static/dialog/resources/state_machine.js
+++ b/resources/static/dialog/resources/state_machine.js
@@ -38,6 +38,7 @@
   var bid = BrowserID,
       storage = bid.Storage,
       mediator = bid.Mediator,
+      user = bid.User,
       publish = mediator.publish.bind(mediator),
       subscriptions = [],
       stateStack = [],
@@ -210,7 +211,13 @@
     });
 
     subscribe("email_chosen", function(msg, info) {
-      var idInfo = storage.getEmail(info.email);
+      var email = info.email
+          idInfo = storage.getEmail(email);
+
+      function complete() {
+        info.complete && info.complete();
+      }
+
       if(idInfo) {
         if(idInfo.type === "primary") {
           if(idInfo.cert) {
@@ -226,7 +233,19 @@
           }
         }
         else {
-          startState("doEmailChosen", info);
+          user.checkAuthentication(function(authentication) {
+            if(authentication === "assertion") {
+              startState("doAuthenticateWithRequiredEmail", {
+                email: email,
+                authenticated: false,
+                secondary_auth: true
+              });
+            }
+            else {
+              startState("doEmailChosen", info);
+            }
+            complete();
+          }, complete);
         }
       }
       else {
diff --git a/resources/static/dialog/views/required_email.ejs b/resources/static/dialog/views/required_email.ejs
index 7c562127a..1f3a188eb 100644
--- a/resources/static/dialog/views/required_email.ejs
+++ b/resources/static/dialog/views/required_email.ejs
@@ -1,4 +1,10 @@
-  <strong>The site requested you sign in using</strong>
+  <strong>
+    <% if(secondary_auth) { %>
+      Sign in using
+    <% } else { %>
+      The site requested you sign in using
+    <% } %>
+  </strong>
   <div class="form_section">
       <ul class="inputs">
 
diff --git a/resources/static/shared/network.js b/resources/static/shared/network.js
index 627417493..b1687c5b9 100644
--- a/resources/static/shared/network.js
+++ b/resources/static/shared/network.js
@@ -117,7 +117,7 @@ BrowserID.Network = (function() {
   }
 
   function withContext(cb, onFailure) {
-    if (typeof auth_status === 'boolean' && typeof csrf_token !== 'undefined') cb();
+    if (typeof auth_status !== 'undefined' && typeof csrf_token !== 'undefined') cb();
     else {
       var url = "/wsapi/session_context";
       xhr.ajax({
@@ -155,7 +155,7 @@ BrowserID.Network = (function() {
     csrf_token = server_time = auth_status = undef;
   }
 
-  function handleAuthenticationResponse(onComplete, onFailure, status) {
+  function handleAuthenticationResponse(type, onComplete, onFailure, status) {
     if (onComplete) {
       try {
         var authenticated = status.success;
@@ -165,7 +165,7 @@ BrowserID.Network = (function() {
         // at this point we know the authentication status of the
         // session, let's set it to perhaps save a network request
         // (to fetch session context).
-        auth_status = authenticated;
+        auth_status = authenticated && type;
         if (onComplete) onComplete(authenticated);
       } catch (e) {
         onFailure("unexpected server response: " + e);
@@ -205,7 +205,7 @@ BrowserID.Network = (function() {
           email: email,
           pass: password
         },
-        success: handleAuthenticationResponse.bind(null, onComplete, onFailure),
+        success: handleAuthenticationResponse.curry("password", onComplete, onFailure),
         error: onFailure
       });
     },
@@ -226,7 +226,7 @@ BrowserID.Network = (function() {
           email: email,
           assertion: assertion
         },
-        success: handleAuthenticationResponse.bind(null, onComplete, onFailure),
+        success: handleAuthenticationResponse.curry("assertion", onComplete, onFailure),
         error: onFailure
       });
     },
@@ -241,7 +241,7 @@ BrowserID.Network = (function() {
     checkAuth: function(onComplete, onFailure) {
       withContext(function() {
         try {
-          if (typeof auth_status !== 'boolean') throw "can't get authentication status!";
+          if (typeof auth_status === 'undefined') throw "can't get authentication status!";
           if (onComplete) onComplete(auth_status);
         } catch(e) {
           if (onFailure) onFailure(e.toString());
diff --git a/resources/static/test/qunit/controllers/primary_user_provisioned_unit_test.js b/resources/static/test/qunit/controllers/primary_user_provisioned_unit_test.js
index e78de4af4..10fae255a 100644
--- a/resources/static/test/qunit/controllers/primary_user_provisioned_unit_test.js
+++ b/resources/static/test/qunit/controllers/primary_user_provisioned_unit_test.js
@@ -115,7 +115,7 @@
   asyncTest("start controller with `add: false` authenticates user", function() {
     register("primary_user_ready", function(msg, info) {
       network.checkAuth(function(status) {
-        equal(status, true, "status is correct");
+        equal(status, "assertion", "status is correct");
         start();
       });
     });
diff --git a/resources/static/test/qunit/resources/state_machine_unit_test.js b/resources/static/test/qunit/resources/state_machine_unit_test.js
index d0df3c9e6..f02af9d7f 100644
--- a/resources/static/test/qunit/resources/state_machine_unit_test.js
+++ b/resources/static/test/qunit/resources/state_machine_unit_test.js
@@ -42,7 +42,8 @@
       machine,
       actions,
       storage = bid.Storage,
-      testHelpers = bid.TestHelpers;
+      testHelpers = bid.TestHelpers,
+      xhr = bid.Mocks.xhr;
 
   var ActionsMock = function() {
     this.called = {};
@@ -261,16 +262,33 @@
   });
 
 
-  test("email_chosen with secondary email, user must authenticate - call doAuthenticateWithRequiredEmail", function() {
+  asyncTest("email_chosen with secondary email, user must authenticate - call doAuthenticateWithRequiredEmail", function() {
+    var email = "testuser@testuser.com";
+    storage.addEmail(email, { type: "secondary" });
 
+    xhr.setContextInfo("authenticated", "assertion");
+
+    mediator.publish("email_chosen", {
+      email: email,
+      complete: function() {
+        equal(actions.called.doAuthenticateWithRequiredEmail, true, "doAuthenticateWithRequiredEmail called");
+        start();
+      }
+    });
   });
 
-  test("email_chosen with secondary email, user authenticated to secondary - call doEmailChosen", function() {
+  asyncTest("email_chosen with secondary email, user authenticated to secondary - call doEmailChosen", function() {
     var email = "testuser@testuser.com";
     storage.addEmail(email, { type: "secondary" });
-    mediator.publish("email_chosen", { email: email });
-
-    equal(actions.called.doEmailChosen, true, "doEmailChosen called");
+    xhr.setContextInfo("authenticated", "password");
+
+    mediator.publish("email_chosen", {
+      email: email,
+      complete: function() {
+        equal(actions.called.doEmailChosen, true, "doEmailChosen called");
+        start();
+      }
+    });
   });
 
   test("email_chosen with primary email - call doProvisionPrimaryUser", function() {
diff --git a/resources/static/test/qunit/shared/user_unit_test.js b/resources/static/test/qunit/shared/user_unit_test.js
index 50564754d..733e48d2e 100644
--- a/resources/static/test/qunit/shared/user_unit_test.js
+++ b/resources/static/test/qunit/shared/user_unit_test.js
@@ -200,7 +200,7 @@ var vep = require("./vep");
     lib.createUser("unregistered@testuser.com", function(status) {
       equal(status, "primary.verified", "primary user is already verified, correct status");
       network.checkAuth(function(authenticated) {
-        equal(authenticated, true, "after provisioning user, user should be automatically authenticated to BrowserID");
+        equal(authenticated, "assertion", "after provisioning user, user should be automatically authenticated to BrowserID");
         start();
       });
     }, testHelpers.unexpectedXHRFailure);
diff --git a/resources/static/test/qunit/testHelpers/helpers.js b/resources/static/test/qunit/testHelpers/helpers.js
index a131da0ce..9e19c32b9 100644
--- a/resources/static/test/qunit/testHelpers/helpers.js
+++ b/resources/static/test/qunit/testHelpers/helpers.js
@@ -41,6 +41,7 @@
   BrowserID.TestHelpers = {
     setup: function() {
       network.setXHR(xhr);
+      //xhr.setContextInfo("authenticated", false);
       xhr.useResult("valid");
       storage.clear();
 
-- 
GitLab