Bug 963835 - B2G fixes for FxA client handle incorrect capitalization in emails. r=ferjm

This commit is contained in:
Jed Parsons 2014-01-31 15:21:46 -08:00
parent 8a0703c1c2
commit 7799cc441b
5 changed files with 213 additions and 23 deletions

View File

@ -39,7 +39,7 @@ this.FxAccountsMgmtService = {
this._shell.sendCustomEvent(aEventName, aMsg);
},
_onFullfill: function(aMsgId, aData) {
_onFulfill: function(aMsgId, aData) {
this._sendChromeEvent("mozFxAccountsChromeEvent", {
id: aMsgId,
data: aData ? aData : null
@ -100,7 +100,7 @@ this.FxAccountsMgmtService = {
FxAccountsManager.getAccount().then(
account => {
// We only expose the email and verification status so far.
self._onFullfill(msg.id, account);
self._onFulfill(msg.id, account);
},
reason => {
self._onReject(msg.id, reason);
@ -110,7 +110,7 @@ this.FxAccountsMgmtService = {
case "logout":
FxAccountsManager.signOut().then(
() => {
self._onFullfill(msg.id);
self._onFulfill(msg.id);
},
reason => {
self._onReject(msg.id, reason);
@ -120,7 +120,7 @@ this.FxAccountsMgmtService = {
case "queryAccount":
FxAccountsManager.queryAccount(data.accountId).then(
result => {
self._onFullfill(msg.id, result);
self._onFulfill(msg.id, result);
},
reason => {
self._onReject(msg.id, reason);
@ -132,7 +132,7 @@ this.FxAccountsMgmtService = {
case "refreshAuthentication":
FxAccountsManager[data.method](data.accountId, data.password).then(
user => {
self._onFullfill(msg.id, user);
self._onFulfill(msg.id, user);
},
reason => {
self._onReject(msg.id, reason);

View File

@ -0,0 +1,184 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://services-common/utils.js");
Cu.import("resource://testing-common/httpd.js");
XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsMgmtService",
"resource://gre/modules/FxAccountsMgmtService.jsm",
"FxAccountsMgmtService");
// At end of test, restore original state
const ORIGINAL_AUTH_URI = Services.prefs.getCharPref("identity.fxaccounts.auth.uri");
const ORIGINAL_SHELL = FxAccountsMgmtService._shell;
do_register_cleanup(function() {
Services.prefs.setCharPref("identity.fxaccounts.auth.uri", ORIGINAL_AUTH_URI);
FxAccountsMgmtService._shell = ORIGINAL_SHELL;
});
// Make profile available so that fxaccounts can store user data
do_get_profile();
// Mock the b2g shell; make message passing possible
let mockShell = {
sendCustomEvent: function(aEventName, aMsg) {
Services.obs.notifyObservers({wrappedJSObject: aMsg}, aEventName, null);
},
};
function run_test() {
run_next_test();
}
add_task(function test_overall() {
do_check_neq(FxAccountsMgmtService, null);
});
// Check that invalid email capitalization is corrected on signIn.
// https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#post-v1accountlogin
add_test(function test_invalidEmailCase_signIn() {
do_test_pending();
let clientEmail = "greta.garbo@gmail.com";
let canonicalEmail = "Greta.Garbo@gmail.COM";
let attempts = 0;
function writeResp(response, msg) {
if (typeof msg === "object") {
msg = JSON.stringify(msg);
}
response.bodyOutputStream.write(msg, msg.length);
}
// Mock of the fxa accounts auth server, reproducing the behavior of
// /account/login when email capitalization is incorrect on signIn.
let server = httpd_setup({
"/account/login": function(request, response) {
response.setHeader("Content-Type", "application/json");
attempts += 1;
// Ensure we don't get in an endless loop
if (attempts > 2) {
response.setStatusLine(request.httpVersion, 429, "Sorry, you had your chance");
writeResp(response, {});
return;
}
let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
let jsonBody = JSON.parse(body);
let email = jsonBody.email;
// The second time through, the accounts client will call the api with
// the correct email capitalization.
if (email == canonicalEmail) {
response.setStatusLine(request.httpVersion, 200, "Yay");
writeResp(response, {
uid: "your-uid",
sessionToken: "your-sessionToken",
keyFetchToken: "your-keyFetchToken",
verified: true,
authAt: 1392144866,
});
return;
}
// If the client has the wrong case on the email, we return a 400, with
// the capitalization of the email as saved in the accounts database.
response.setStatusLine(request.httpVersion, 400, "Incorrect email case");
writeResp(response, {
code: 400,
errno: 120,
error: "Incorrect email case",
email: canonicalEmail,
});
return;
},
});
// Point the FxAccountsClient's hawk rest request client to the mock server
Services.prefs.setCharPref("identity.fxaccounts.auth.uri", server.baseURI);
// Receive a mozFxAccountsChromeEvent message
function onMessage(subject, topic, data) {
let message = subject.wrappedJSObject;
switch (message.id) {
// When we signed in as "Greta.Garbo", the server should have told us
// that the proper capitalization is really "greta.garbo". Call
// getAccounts to get the signed-in user and ensure that the
// capitalization is correct.
case "signIn":
FxAccountsMgmtService.handleEvent({
detail: {
id: "getAccounts",
data: {
method: "getAccounts",
}
}
});
break;
// Having initially signed in as "Greta.Garbo", getAccounts should show
// us that the signed-in user has the properly-capitalized email,
// "greta.garbo".
case "getAccounts":
Services.obs.removeObserver(onMessage, "mozFxAccountsChromeEvent");
do_check_eq(message.data.accountId, canonicalEmail);
do_test_finished();
server.stop(run_next_test);
break;
// We should not receive any other mozFxAccountsChromeEvent messages
default:
do_throw("wat!");
break;
}
}
Services.obs.addObserver(onMessage, "mozFxAccountsChromeEvent", false);
FxAccountsMgmtService._shell = mockShell;
// Trigger signIn using an email with incorrect capitalization
FxAccountsMgmtService.handleEvent({
detail: {
id: "signIn",
data: {
method: "signIn",
accountId: clientEmail,
password: "123456",
},
},
});
});
// End of tests
// Utility functions follow
function httpd_setup (handlers, port=-1) {
let server = new HttpServer();
for (let path in handlers) {
server.registerPathHandler(path, handlers[path]);
}
try {
server.start(port);
} catch (ex) {
dump("ERROR starting server on port " + port + ". Already a process listening?");
do_throw(ex);
}
// Set the base URI for convenience.
let i = server.identity;
server.baseURI = i.primaryScheme + "://" + i.primaryHost + ":" + i.primaryPort;
return server;
}

View File

@ -6,6 +6,7 @@ tail =
[test_bug832946.js]
[test_fxaccounts.js]
[test_signintowebsite.js]
head = head_identity.js
tail =

View File

@ -21,9 +21,6 @@ Cu.import("resource://gre/modules/FxAccounts.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/FxAccountsCommon.js");
XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsClient",
"resource://gre/modules/FxAccountsClient.jsm");
this.FxAccountsManager = {
init: function() {
@ -83,10 +80,13 @@ this.FxAccountsManager = {
return this._error(error ? error : ERROR_SERVER_ERROR, aServerResponse);
},
// As we do with _fxAccounts, we don't really need this factory, but this way
// we allow tests to mock FxAccountsClient.
_createFxAccountsClient: function() {
return new FxAccountsClient();
// As with _fxAccounts, we don't really need this method, but this way we
// allow tests to mock FxAccountsClient. By default, we want to return the
// client used by the fxAccounts object because deep down they should have
// access to the same hawk request object which will enable them to share
// local clock skeq data.
_getFxAccountsClient: function() {
return this._fxAccounts.getAccountsClient();
},
_signInSignUp: function(aMethod, aAccountId, aPassword) {
@ -109,7 +109,7 @@ this.FxAccountsManager = {
});
}
let client = this._createFxAccountsClient();
let client = this._getFxAccountsClient();
return this._fxAccounts.getSignedInUser().then(
user => {
if (user) {
@ -128,9 +128,11 @@ this.FxAccountsManager = {
});
}
// Save the credentials of the signed in user.
user.email = aAccountId;
return this._fxAccounts.setSignedInUser(user, false).then(
// If the user object includes an email field, it may differ in
// capitalization from what we sent down. This is the server's
// canonical capitalization and should be used instead.
user.email = user.email || aAccountId;
return this._fxAccounts.setSignedInUser(user).then(
() => {
this._activeSession = user;
log.debug("User signed in: " + JSON.stringify(this._user) +
@ -171,7 +173,7 @@ this.FxAccountsManager = {
return Promise.resolve();
}
// Otherwise, we try to remove the remote session.
let client = this._createFxAccountsClient();
let client = this._getFxAccountsClient();
return client.signOut(sessionToken).then(
result => {
let error = this._getError(result);
@ -293,7 +295,7 @@ this.FxAccountsManager = {
return this._error(ERROR_INVALID_ACCOUNTID);
}
let client = this._createFxAccountsClient();
let client = this._getFxAccountsClient();
return client.accountExists(aAccountId).then(
result => {
log.debug("Account " + result ? "" : "does not" + " exists");
@ -327,7 +329,7 @@ this.FxAccountsManager = {
return this._error(ERROR_OFFLINE);
}
let client = this._createFxAccountsClient();
let client = this._getFxAccountsClient();
return client.recoveryEmailStatus(this._activeSession.sessionToken).then(
data => {
let error = this._getError(data);

View File

@ -140,7 +140,8 @@ FxAccountsManager._fxAccounts = {
};
// Save original FxAccountsClient factory from FxAccountsManager.
const kFxAccountsClient = FxAccountsManager._createFxAccountsClient;
const kFxAccountsClient = FxAccountsManager._getFxAccountsClient;
// and change it for a fake client factory.
let FakeFxAccountsClient = {
_reject: false,
@ -201,9 +202,11 @@ let FakeFxAccountsClient = {
return deferred.promise;
}
};
FxAccountsManager._createFxAccountsClient = function() {
FxAccountsManager._getFxAccountsClient = function() {
return FakeFxAccountsClient;
}
};
// === Global cleanup ===
@ -225,7 +228,7 @@ do_register_cleanup(function() {
FxAccountsManager._fxAccounts = kFxAccounts;
// Restore the FxAccountsClient getter from FxAccountsManager.
FxAccountsManager._createFxAccountsClient = kFxAccountsClient;
FxAccountsManager._getFxAccountsClient = kFxAccountsClient;
});