diff --git a/bin/load_gen b/bin/load_gen index b34ac3ff13c752f4c156000bffe3c1048ba25fd7..8acfdadefccd84350de509530fc36c0a6692e444 100755 --- a/bin/load_gen +++ b/bin/load_gen @@ -281,7 +281,7 @@ function poll() { } // always start out by creating a bunch of users -var NUM_INITIAL_USERS = 5; +var NUM_INITIAL_USERS = 30; // if an explicit target was specified, let's output what that means // in understandable terms diff --git a/lib/load_gen/crypto.js b/lib/load_gen/crypto.js new file mode 100644 index 0000000000000000000000000000000000000000..aa4735336dfb153739f14587362631c65b9e9311 --- /dev/null +++ b/lib/load_gen/crypto.js @@ -0,0 +1,38 @@ +// a little tiny task focused wrapper around the excellent api exposed by +// jwcrypto + +const +userDB = require('./user_db.js'), +jwk = require('jwcrypto/jwk.js'), +jwt = require('jwcrypto/jwt.js'), +vep = require('jwcrypto/vep.js'); + +const NUM_KEYPAIRS = 5; + +process.stdout.write("generating " + NUM_KEYPAIRS + + " keypairs to be (re)used during load generation: "); + +var keyPairs = []; + +while (keyPairs.length < NUM_KEYPAIRS) +{ + keyPairs.push(jwk.KeyPair.generate("DS", 256)); + process.stdout.write("."); +} + +process.stdout.write("\n"); + + +exports.getKeyPair = function() { + return userDB.any(keyPairs); +}; + +exports.getAssertion = function(obj) { + // XXX: we can memoize here at some point, returning existing assertions + // to reduce compute cost of loadgen client, to simulate more load + // on servers + var expirationDate = new Date(obj.now.getTime() + (2 * 60 * 1000)); + var tok = new jwt.JWT(null, expirationDate, obj.audience); + var assertion = vep.bundleCertsAndAssertion([obj.cert], tok.sign(obj.secretKey)); + return assertion; +}; diff --git a/lib/load_gen/signin.js b/lib/load_gen/signin.js index 49a0030e5677adccae74680ca47b9b157a639e0e..5695dddf2c7ba80eda0894b21f611ce5aa9d8914 100644 --- a/lib/load_gen/signin.js +++ b/lib/load_gen/signin.js @@ -41,7 +41,8 @@ const wcli = require("../wsapi_client.js"), userdb = require("./user_db.js"), -winston = require('winston'); +winston = require('winston'), +crypto = require('./crypto'); exports.startFunc = function(cfg, cb) { @@ -54,12 +55,28 @@ exports.startFunc = function(cfg, cb) { var user = userdb.getExistingUser(); + if (!user) { + winston.warn("can't achieve desired concurrency! not enough users!"); + return cb(false); + } + + // unlock the user when we're done with them + cb = (function() { + var _cb = cb; + return function(x) { + userdb.releaseUser(user); + _cb(x); + }; + })(); + // pick one of the user's emails that we'll use var email = userdb.any(user.emails); // pick one of the user's devices that we'll use var context = userdb.any(user.ctxs); + var origin = userdb.any(user.sites); + // we want session_context to be called to simulate actual users. wcli.get(cfg, '/wsapi/session_context', context, undefined, function (r) { var serverTime; @@ -83,10 +100,24 @@ exports.startFunc = function(cfg, cb) { return cb(false); } - // XXX: write me - process.exit(1); + var assertion = crypto.getAssertion({ + now: serverTime, + secretKey: context.keys[email].keyPair.secretKey, + cert: context.keys[email].cert, + audience: origin, + email: email + }); + + wcli.post(cfg, '/verify', {}, { + audience: origin, + assertion: assertion + }, function (r) { + try { + cb(JSON.parse(r.body).status === 'okay'); + } catch(e) { + return cb(false); + } + }); }); }); - - setTimeout(function() { cb(true); }, 10); }; diff --git a/lib/load_gen/signup.js b/lib/load_gen/signup.js index c508976254b5917deb98a1a074a181b72034eb74..ed402c6313ee37ca6e8fe29b319e9fcf9d1a6af7 100644 --- a/lib/load_gen/signup.js +++ b/lib/load_gen/signup.js @@ -38,7 +38,7 @@ const wcli = require("../wsapi_client.js"), userdb = require("./user_db.js"), winston = require('winston'), -keys = require("./test_keys.js"); +crypto = require("./crypto.js"); /* this file is the "signup" activity, which simulates the process of a new user * signing up for browserid. */ @@ -68,8 +68,8 @@ exports.startFunc = function(cfg, cb) { var user = userdb.getNewUser(); if (!user) { - winston.warn("can't achieve desired concurrency! not enough users!"); - return cb(false); + winston.error(".getNewUser() should *never* return undefined!"); + process.exit(1); } // unlock the user when we're done with them @@ -109,8 +109,7 @@ exports.startFunc = function(cfg, cb) { r.body = JSON.parse(r.body); if (r.code !== 200 || r.body.success !== true) return cb(false); - // and now we should call registration status to complete the - // process + // and now let's certify the pubkey wcli.post(cfg, '/wsapi/cert_key', context, { email: email, pubkey: keypair.publicKey.serialize() diff --git a/lib/load_gen/test_keys.js b/lib/load_gen/test_keys.js deleted file mode 100644 index e6ccaf2c5338c8c7006914f472169c43fae216ec..0000000000000000000000000000000000000000 --- a/lib/load_gen/test_keys.js +++ /dev/null @@ -1,16 +0,0 @@ -var jwk = require('jwcrypto/jwk'); - -const NUM_KEYPAIRS = 30; - -process.stdout.write("generating " + NUM_KEYPAIRS + - " keypairs to be (re)used in load generation: "); - -exports.keyPairs = []; - -while (exports.keyPairs.length < NUM_KEYPAIRS) -{ - exports.keyPairs.push(jwk.KeyPair.generate("DS", 256)); - process.stdout.write("."); -} - -process.stdout.write("\n"); diff --git a/lib/load_gen/user_db.js b/lib/load_gen/user_db.js index b7c09ce174ded5fc828f40f6daf3ed8f531c3bee..799e8a2435419e12ba4ceef7d8f45b853a6a9a90 100644 --- a/lib/load_gen/user_db.js +++ b/lib/load_gen/user_db.js @@ -40,7 +40,7 @@ const secrets = require('../secrets.js'), -keys = require("./test_keys.js"); +crypto = require("./crypto.js"); // the grandiose database var users = [ ]; @@ -70,10 +70,10 @@ exports.getNewUser = function() { password: secrets.generate(10), // and four sites that they visit sites: [ - secrets.generate(8) + "." + secrets.generate(3), - secrets.generate(8) + "." + secrets.generate(3), - secrets.generate(8) + "." + secrets.generate(3), - secrets.generate(8) + "." + secrets.generate(3) + 'http://' + secrets.generate(8) + "." + secrets.generate(3), + 'http://' + secrets.generate(8) + "." + secrets.generate(3), + 'http://' + secrets.generate(8) + "." + secrets.generate(3), + 'http://' + secrets.generate(8) + "." + secrets.generate(3) ], // and their device contexts (they have 2 devices on average) // key material is device specific @@ -128,7 +128,7 @@ exports.addKeyToUserCtx = function(ctx, email) { // this is simulated. it will need to be real to apply load to // the verifier, but that in turn will drastically increase the // cost of the application of load. ho hum. - var k = exports.any(keys.keyPairs); + var k = crypto.getKeyPair(); ctx.keys[email] = { keyPair: k }; return k; };