From d9c8628d303f367b53eea561765b45dd61da446b Mon Sep 17 00:00:00 2001
From: Lloyd Hilaiel <lloyd@hilaiel.com>
Date: Mon, 16 Jul 2012 16:44:04 -0600
Subject: [PATCH] Allow assertions issued by person to be used to authenticate.
  This makes it possible for "proxy idps" to work without the implementation
 details leaking out into others verifier implementations.

---
 lib/primary.js          | 18 ++++++++++----
 tests/lib/primary.js    | 12 +++++-----
 tests/proxy-idp-test.js | 53 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 72 insertions(+), 11 deletions(-)

diff --git a/lib/primary.js b/lib/primary.js
index f89ba0111..4cccbe295 100644
--- a/lib/primary.js
+++ b/lib/primary.js
@@ -12,7 +12,8 @@ http = require('http'),
 logger = require('./logging.js').logger,
 urlparse = require('urlparse'),
 jwcrypto = require("jwcrypto"),
-config = require("./configuration.js");
+config = require("./configuration.js"),
+secrets = require("./secrets.js");
 
 // alg
 require("jwcrypto/lib/algs/rs");
@@ -27,6 +28,14 @@ const HOSTNAME = urlparse(config.get('public_url')).host;
 
 var g_shim_cache = {};
 
+try {
+  const PUBLIC_KEY = secrets.loadPublicKey();
+  if (typeof PUBLIC_KEY !== 'object') throw "secrets.loadPublicKey() returns non-object, load failure";
+} catch(e){
+  logger.error("can't read public key, exiting: " + e);
+  setTimeout(function() { process.exit(1); }, 0);
+}
+
 // This becomes async
 function parseWellKnownBody(body, domain, delegates, cb) {
   try {
@@ -274,9 +283,10 @@ exports.verifyAssertion = function(assertion, cb) {
   }
 
   var getRoot = function(issuer, next) {
-    // issuer cannot be the browserid
+    // allow assertions rooted in certs issued by us.  this occurs in the proxy_idp case
+    // where we sign assertions for other domains.
     if (issuer === HOSTNAME) {
-      next("cannot authenticate to browserid with a certificate issued by it.");
+      next(null, PUBLIC_KEY);
     } else {
       exports.getPublicKey(issuer, function(err, pubKey) {
         if (err) return next(err);
@@ -293,7 +303,7 @@ exports.verifyAssertion = function(assertion, cb) {
     // for now, to be extra safe, we don't allow cert chains
     if (certParamsArray.length > 1)
       return cb("certificate chaining is not yet allowed");
-    
+
     // audience must be browserid itself
     var want = urlparse(config.get('public_url')).originOnly();
     var got = urlparse(assertionParams.audience).originOnly();
diff --git a/tests/lib/primary.js b/tests/lib/primary.js
index 1ff1b4d77..40d3a5200 100644
--- a/tests/lib/primary.js
+++ b/tests/lib/primary.js
@@ -24,18 +24,18 @@ User.prototype.setup = function(cb) {
   // upon allocation of a user, we'll gen a keypair and get a signed cert
   jwcrypto.generateKeypair({algorithm:"DS", keysize:256}, function(err, kp) {
     if (err) return cb(err);
-    
+
     self._keyPair = kp;
-    
+
     var expiration = new Date();
     expiration.setTime(new Date().valueOf() + 60 * 60 * 1000);
-    
+
     jwcrypto.cert.sign(self._keyPair.publicKey, {email: self.options.email},
                        {expiresAt: expiration, issuer: self.options.domain, issuedAt: new Date()},
-                       {}, g_privKey, function(err, signedCert) {
+                       {}, self.options.privKey || g_privKey, function(err, signedCert) {
                          if (err) return cb(err);
                          self._cert = signedCert;
-                         
+
                          cb(null);
                        });
   });
@@ -52,4 +52,4 @@ User.prototype.getAssertion = function(origin, cb) {
                          });
 };
 
-module.exports = User;
\ No newline at end of file
+module.exports = User;
diff --git a/tests/proxy-idp-test.js b/tests/proxy-idp-test.js
index f8d4685f6..1321c5c6e 100755
--- a/tests/proxy-idp-test.js
+++ b/tests/proxy-idp-test.js
@@ -12,7 +12,12 @@ vows = require('vows'),
 path = require('path'),
 start_stop = require('./lib/start-stop.js'),
 wsapi = require('./lib/wsapi.js'),
-util = require('util');
+primary = require('./lib/primary.js'),
+util = require('util'),
+jwcrypto = require('jwcrypto');
+
+require("jwcrypto/lib/algs/rs");
+require("jwcrypto/lib/algs/ds");
 
 var suite = vows.describe('delegated-primary');
 
@@ -76,6 +81,52 @@ suite.addBatch({
   }
 });
 
+// and now let's verify a primary
+var primaryUser = new primary({
+  email: "bartholomew@yahoo.com",
+  domain: "127.0.0.1",
+  privKey: jwcrypto.loadSecretKey(
+    require('fs').readFileSync(
+      path.join(__dirname, '..', 'var', 'root.secretkey')))
+});
+
+suite.addBatch({
+  "set things up": {
+    topic: function() {
+      primaryUser.setup(this.callback);
+    },
+    "works": function() {
+      // nothing to do here
+    }
+  }
+});
+
+// now let's generate an assertion using this user
+suite.addBatch({
+  "generating an assertion": {
+    topic: function() {
+      primaryUser.getAssertion('http://127.0.0.1:10002', this.callback);
+    },
+    "succeeds": function(err, r) {
+      assert.isString(r);
+    },
+    "and logging in with the assertion succeeds": {
+      topic: function(err, assertion)  {
+        wsapi.post('/wsapi/auth_with_assertion', {
+          assertion: assertion,
+          ephemeral: true
+        }).call(this);
+      },
+      "works": function(err, r) {
+        var resp = JSON.parse(r.body);
+        console.log(resp);
+        assert.isObject(resp);
+        assert.isTrue(resp.success);
+      }
+    }
+  }
+});
+
 start_stop.addShutdownBatches(suite);
 
 // run or export the suite.
-- 
GitLab