diff --git a/resources/static/common/js/user.js b/resources/static/common/js/user.js index be52ee35266f6b908a78941a889ba4200239336c..b1be1696d9d8cddb49f66ba00eaa51f88060a168 100644 --- a/resources/static/common/js/user.js +++ b/resources/static/common/js/user.js @@ -965,8 +965,14 @@ BrowserID.User = (function() { */ syncEmailKeypair: function(email, onComplete, onFailure) { prepareDeps(); - jwcrypto.generateKeypair({algorithm: "DS", keysize: bid.KEY_LENGTH}, function(err, keypair) { - certifyEmailKeypair(email, keypair, onComplete, onFailure); + // jwcrypto depends on a random seed being set to generate a keypair. + // The seed is set with a call to network.withContext. Ensure the + // random seed is set before continuing or else the seed may not be set, + // the key never created, and the onComplete callback never called. + network.withContext(function() { + jwcrypto.generateKeypair({algorithm: "DS", keysize: bid.KEY_LENGTH}, function(err, keypair) { + certifyEmailKeypair(email, keypair, onComplete, onFailure); + }); }); }, diff --git a/resources/static/test/cases/common/js/user.js b/resources/static/test/cases/common/js/user.js index fe0d5c491a5f7779179d96eb7a8e1d3ac67015b8..8713e750ffe2d67d86d74d2de0362bb43db82a2d 100644 --- a/resources/static/test/cases/common/js/user.js +++ b/resources/static/test/cases/common/js/user.js @@ -175,15 +175,14 @@ var jwcrypto = require("./lib/jwcrypto"); asyncTest("createPrimaryUser with primary, user verified with primary - expect 'primary.verified'", function() { xhr.useResult("primary"); - provisioning.setStatus(provisioning.AUTHENTICATED, function() { - lib.createPrimaryUser({email: "unregistered@testuser.com"}, function(status) { - equal(status, "primary.verified", "primary user is already verified, correct status"); - network.checkAuth(function(authenticated) { - equal(authenticated, "assertion", "after provisioning user, user should be automatically authenticated to Persona"); - start(); - }); - }, testHelpers.unexpectedXHRFailure); - }); + provisioning.setStatus(provisioning.AUTHENTICATED); + lib.createPrimaryUser({email: "unregistered@testuser.com"}, function(status) { + equal(status, "primary.verified", "primary user is already verified, correct status"); + network.checkAuth(function(authenticated) { + equal(authenticated, "assertion", "after provisioning user, user should be automatically authenticated to Persona"); + start(); + }); + }, testHelpers.unexpectedXHRFailure); }); asyncTest("createPrimaryUser with primary, user must authenticate with primary - expect 'primary.verify'", function() { diff --git a/resources/static/test/cases/dialog/js/modules/provision_primary_user.js b/resources/static/test/cases/dialog/js/modules/provision_primary_user.js index f5464f9164042a724020a86deaec3742329cdea8..d5c540849802c80b10796e8efd7677491cb51645 100644 --- a/resources/static/test/cases/dialog/js/modules/provision_primary_user.js +++ b/resources/static/test/cases/dialog/js/modules/provision_primary_user.js @@ -10,6 +10,7 @@ bid = BrowserID, storage = bid.Storage, user = bid.User, + network = bid.Network, register = bid.TestHelpers.register, xhr = bid.Mocks.xhr, mediator = bid.Mediator, @@ -56,6 +57,7 @@ asyncTest("create controller with all fields specified, user authenticated with primary - expected user provisioned", function() { provisioning.setStatus(provisioning.AUTHENTICATED); + xhr.useResult("primary"); mediator.subscribe("primary_user_provisioned", function(msg, info) { ok(info.assertion, "assertion available"); @@ -72,6 +74,7 @@ asyncTest("create controller with all fields specified, user not authenticated with primary - expected user must authenticate", function() { provisioning.setStatus(provisioning.NOT_AUTHENTICATED); + xhr.useResult("primary"); mediator.subscribe("primary_user_unauthenticated", function(msg, info) { equal(info.auth_url, "https://auth_url", "primary information fetched"); @@ -86,8 +89,8 @@ }); asyncTest("create controller with missing auth/prov, user authenticated with primary - expected to request provisioning info from backend, user provisioned", function() { - xhr.useResult("primary"); provisioning.setStatus(provisioning.AUTHENTICATED); + xhr.useResult("primary"); mediator.subscribe("primary_user_provisioned", function(msg, info) { equal(info.email, "unregistered@testuser.com", "user is provisioned after requesting info from backend"); diff --git a/resources/static/test/mocks/provisioning.js b/resources/static/test/mocks/provisioning.js index a752881df1b345843f3ab388b465ff43b90d5905..13907e4d7b981c59658f65268b32cec9f8cdfe8c 100644 --- a/resources/static/test/mocks/provisioning.js +++ b/resources/static/test/mocks/provisioning.js @@ -16,12 +16,26 @@ BrowserID.Mocks.Provisioning = (function() { function Provisioning(info, onsuccess, onfailure) { if(status === Provisioning.AUTHENTICATED) { - onsuccess(keypair, cert); + if (!keypair) { + // JWCrypto relies on there being a random seed. The random seed is + // gotten whenever network.withContext is called. Since this is + // supposed to mock the IdP provisioning step which will not call + // network.withContext, add a random seed to ensure that we can get our + // keypair. + jwcrypto.addEntropy("H+ZgKuhjVckv/H4i0Qvj/JGJEGDVOXSIS5RCOjY9/Bo="); + jwcrypto.generateKeypair({algorithm: "DS", keysize: 256}, function(err, kp) { + keypair = kp; + if (onsuccess) onsuccess(keypair, cert); + }); + } + else { + if (onsuccess) onsuccess(keypair, cert); + } } else onfailure(failure); } - Provisioning.setStatus = function(newStatus, cb) { + Provisioning.setStatus = function(newStatus) { failure = null; status = newStatus; @@ -31,14 +45,6 @@ BrowserID.Mocks.Provisioning = (function() { code: "primaryError", msg: "user is not authenticated as target user" }; - if (cb) cb(); - } - else if(newStatus === Provisioning.AUTHENTICATED) { - if (!keypair) - jwcrypto.generateKeypair({algorithm: "DS", keysize: 256}, function(err, kp) { - keypair = kp; - if (cb) cb(); - }); } };