Bug 981921 - Allow signin in FxAccountsClient to use '?keys=true'. r=ckarlof
authorHenrik Skupin <mail@hskupin.info>
Wed, 12 Mar 2014 22:50:58 +0100
changeset 173321 478d940d4f1d42799359a3d6574ed0ac1c152f48
parent 173320 27737607943da6fa3855e4f66f6262da341e441b
child 173322 fdbf79a891dec07b8c7da1c9dc6f50cb84867fcb
push id26399
push usercbook@mozilla.com
push dateThu, 13 Mar 2014 11:51:43 +0000
treeherdermozilla-central@fdbf79a891de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckarlof
bugs981921
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 981921 - Allow signin in FxAccountsClient to use '?keys=true'. r=ckarlof
services/fxaccounts/FxAccountsClient.jsm
services/fxaccounts/tests/xpcshell/test_client.js
--- a/services/fxaccounts/FxAccountsClient.jsm
+++ b/services/fxaccounts/FxAccountsClient.jsm
@@ -81,32 +81,41 @@ this.FxAccountsClient.prototype = {
 
   /**
    * Authenticate and create a new session with the Firefox Account API server
    *
    * @param email
    *        The email address for the account (utf8)
    * @param password
    *        The user's password
+   * @param [getKeys=false]
+   *        If set to true the keyFetchToken will be retrieved
+   * @param [retryOK=true]
+   *        If capitalization of the email is wrong and retryOK is set to true,
+   *        we will retry with the suggested capitalization from the server
    * @return Promise
    *        Returns a promise that resolves to an object:
    *        {
    *          uid: the user's unique ID (hex)
    *          sessionToken: a session token (hex)
    *          keyFetchToken: a key fetch token (hex)
    *          verified: flag indicating verification status of the email
+   *          authAt: authentication time for the session (seconds since epoch)
+   *          email: the primary email for this account
    *        }
    */
-  signIn: function signIn(email, password, retryOK=true) {
+  signIn: function signIn(email, password, getKeys=false, retryOK=true) {
     return Credentials.setup(email, password).then((creds) => {
       let data = {
         email: creds.emailUTF8,
         authPW: CommonUtils.bytesAsHex(creds.authPW),
       };
-      return this._request("/account/login", "POST", null, data).then(
+      let keys = getKeys ? "?keys=true" : "";
+
+      return this._request("/account/login" + keys, "POST", null, data).then(
         // Include the canonical capitalization of the email in the response so
         // the caller can set its signed-in user state accordingly.
         result => {
           result.email = data.email;
           return result;
         },
         error => {
           log.debug("signIn error: " + JSON.stringify(error));
@@ -121,17 +130,17 @@ this.FxAccountsClient.prototype = {
           //
           // API reference:
           // https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md
           if (ERRNO_INCORRECT_EMAIL_CASE === error.errno && retryOK) {
             if (!error.email) {
               log.error("Server returned errno 120 but did not provide email");
               throw error;
             }
-            return this.signIn(error.email, password, false);
+            return this.signIn(error.email, password, getKeys, false);
           }
           throw error;
         }
       );
     });
   },
 
   /**
--- a/services/fxaccounts/tests/xpcshell/test_client.js
+++ b/services/fxaccounts/tests/xpcshell/test_client.js
@@ -217,47 +217,103 @@ add_task(function test_signUp() {
   } catch(expectedError) {
     do_check_eq(101, expectedError.errno);
   }
 
   yield deferredStop(server);
 });
 
 add_task(function test_signIn() {
-  let sessionMessage = JSON.stringify({sessionToken: FAKE_SESSION_TOKEN});
-  let errorMessage = JSON.stringify({code: 400, errno: 102, error: "doesn't exist"});
+  let sessionMessage_noKey = JSON.stringify({
+    sessionToken: FAKE_SESSION_TOKEN
+  });
+  let sessionMessage_withKey = JSON.stringify({
+    sessionToken: FAKE_SESSION_TOKEN,
+    keyFetchToken: "keyFetchToken"
+  });
+  let errorMessage_notExistent = JSON.stringify({
+    code: 400,
+    errno: 102,
+    error: "doesn't exist"
+  });
+  let errorMessage_wrongCap = JSON.stringify({
+    code: 400,
+    errno: 120,
+    error: "Incorrect email case",
+    email: "you@example.com"
+  });
 
   let server = httpd_setup({
     "/account/login": function(request, response) {
       let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
       let jsonBody = JSON.parse(body);
 
       if (jsonBody.email == "mé@example.com") {
+        do_check_eq("", request._queryString);
         do_check_eq(jsonBody.authPW, "08b9d111196b8408e8ed92439da49206c8ecfbf343df0ae1ecefcd1e0174a8b6");
         response.setStatusLine(request.httpVersion, 200, "OK");
-        response.bodyOutputStream.write(sessionMessage, sessionMessage.length);
+        response.bodyOutputStream.write(sessionMessage_noKey,
+                                        sessionMessage_noKey.length);
+        return;
+      }
+      else if (jsonBody.email == "you@example.com") {
+        do_check_eq("keys=true", request._queryString);
+        do_check_eq(jsonBody.authPW, "93d20ec50304d496d0707ec20d7e8c89459b6396ec5dd5b9e92809c5e42856c7");
+        response.setStatusLine(request.httpVersion, 200, "OK");
+        response.bodyOutputStream.write(sessionMessage_withKey,
+                                        sessionMessage_withKey.length);
         return;
       }
-
-      // Error trying to sign in to nonexistent account
-      response.setStatusLine(request.httpVersion, 400, "Bad request");
-      response.bodyOutputStream.write(errorMessage, errorMessage.length);
-      return;
+      else if (jsonBody.email == "You@example.com") {
+        // Error trying to sign in with a wrong capitalization
+        response.setStatusLine(request.httpVersion, 400, "Bad request");
+        response.bodyOutputStream.write(errorMessage_wrongCap,
+                                        errorMessage_wrongCap.length);
+        return;
+      }
+      else {
+        // Error trying to sign in to nonexistent account
+        response.setStatusLine(request.httpVersion, 400, "Bad request");
+        response.bodyOutputStream.write(errorMessage_notExistent,
+                                        errorMessage_notExistent.length);
+        return;
+      }
     },
   });
 
+  // Login without retrieving optional keys
   let client = new FxAccountsClient(server.baseURI);
   let result = yield client.signIn('mé@example.com', 'bigsecret');
   do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
+  do_check_eq(undefined, result.keyFetchToken);
+
+  // Login with retrieving optional keys
+  let result = yield client.signIn('you@example.com', 'bigsecret', true);
+  do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
+  do_check_eq("keyFetchToken", result.keyFetchToken);
+
+  // Retry due to wrong email capitalization
+  let result = yield client.signIn('You@example.com', 'bigsecret', true);
+  do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
+  do_check_eq("keyFetchToken", result.keyFetchToken);
+
+  // Don't retry due to wrong email capitalization
+  try {
+    let result = yield client.signIn('You@example.com', 'bigsecret', true, false);
+    do_throw("Expected to catch an exception");
+  } catch (expectedError) {
+    do_check_eq(120, expectedError.errno);
+    do_check_eq("you@example.com", expectedError.email);
+  }
 
   // Trigger error path
   try {
     result = yield client.signIn("yøü@bad.example.org", "nofear");
     do_throw("Expected to catch an exception");
-  } catch(expectedError) {
+  } catch (expectedError) {
     do_check_eq(102, expectedError.errno);
   }
 
   yield deferredStop(server);
 });
 
 add_task(function test_signOut() {
   let signoutMessage = JSON.stringify({});