WIP: switch to authenticated requests

This commit is contained in:
AJ ONeal 2019-05-11 14:34:55 -06:00
parent 8b2e6e69d0
commit 1826ec8497
3 changed files with 34 additions and 15 deletions

View File

@ -685,6 +685,7 @@ function parseConfig(err, text) {
, protected: { , protected: {
// alg will be filled out automatically // alg will be filled out automatically
jwk: state.pub jwk: state.pub
, kid: false
, nonce: nonce , nonce: nonce
, url: newAccountUrl , url: newAccountUrl
} }

View File

@ -590,9 +590,14 @@ function jwtEggspress(req, res, next) {
// TODO verify if possible // TODO verify if possible
console.warn("[warn] JWT is not verified yet"); console.warn("[warn] JWT is not verified yet");
// A failed JWS should cause a failed JWT
if (false !== req.trusted) {
req.trusted = true;
}
next(); next();
} }
// TODO switch to Keypairs.js / Keyfetch.js
function verifyJws(jwk, jws) { function verifyJws(jwk, jws) {
return keypairs.export({ jwk: jwk }).then(function (pem) { return keypairs.export({ jwk: jwk }).then(function (pem) {
var alg = 'SHA' + jws.header.alg.replace(/[^\d]+/i, ''); var alg = 'SHA' + jws.header.alg.replace(/[^\d]+/i, '');
@ -632,9 +637,8 @@ function jwsEggspress(req, res, next) {
} }
if (req.jws.header.jwk) { if (req.jws.header.jwk) {
if (kid) { if (kid) {
// TODO kid and jwk are mutually exclusive res.send({ error: { message: "jws protected header must not include both 'kid' and 'jwk'" } });
//res.send({ error: { message: "jws protected header must not include both 'kid' and 'jwk'" } }); return;
//return;
} }
kid = req.jws.header.jwk.kid; kid = req.jws.header.jwk.kid;
p = Keypairs.thumbprint({ jwk: req.jws.header.jwk }).then(function (thumb) { p = Keypairs.thumbprint({ jwk: req.jws.header.jwk }).then(function (thumb) {
@ -699,6 +703,10 @@ function jwsEggspress(req, res, next) {
}); });
}); });
}).then(function () { }).then(function () {
// a failed JWT should cause a failed JWS
if (false !== req.trusted) {
req.trusted = req.jws.trusted;
}
next(); next();
}); });
} }
@ -1038,10 +1046,19 @@ function handleApi() {
app.head('/acme/new-nonce', controllers.newNonce); app.head('/acme/new-nonce', controllers.newNonce);
app.get('/acme/new-nonce', controllers.newNonce); app.get('/acme/new-nonce', controllers.newNonce);
app.post('/acme/new-acct', controllers.newAccount); app.post('/acme/new-acct', controllers.newAccount);
app.use(/\b(relay)\b/, controllers.relay); function mustTrust(req, res, next) {
app.get(/\b(config)\b/, getConfigOnly); // TODO public routes should be explicitly marked
app.use(/\b(init|config)\b/, initOrConfig); // trusted should be the default
app.use(/\b(restart)\b/, restart); if (req.trusted) { next(); }
res.statusCode = 400;
res.send({"error":{"message": "this type of requests must be encoded as a jws payload"
+ " and signed by a trusted account holder"}});
return;
}
app.use(/\b(relay)\b/, mustTrust, controllers.relay);
app.get(/\b(config)\b/, mustTrust, getConfigOnly);
app.use(/\b(init|config)\b/, mustTrust, initOrConfig);
app.use(/\b(restart)\b/, mustTrust, restart);
// Position is important with eggspress // Position is important with eggspress
// This should stay here, right before the other methods // This should stay here, right before the other methods
@ -1050,14 +1067,14 @@ function handleApi() {
// //
// With proper config // With proper config
// //
app.use(/\b(http)\b/, controllers.http); app.use(/\b(http)\b/, mustTrust, controllers.http);
app.use(/\b(tcp)\b/, controllers.tcp); app.use(/\b(tcp)\b/, mustTrust, controllers.tcp);
app.use(/\b(save|commit)\b/, saveAndCommit); app.use(/\b(save|commit)\b/, mustTrust, saveAndCommit);
app.use(/\b(ssh)\b/, controllers.ssh); app.use(/\b(ssh)\b/, mustTrust, controllers.ssh);
app.use(/\b(enable)\b/, enable); app.use(/\b(enable)\b/, mustTrust, enable);
app.use(/\b(disable)\b/, disable); app.use(/\b(disable)\b/, mustTrust, disable);
app.use(/\b(status)\b/, getStatus); app.use(/\b(status)\b/, mustTrust, getStatus);
app.use(/\b(list)\b/, listSuccess); app.use(/\b(list)\b/, mustTrust, listSuccess);
app.use('/', function (req, res) { app.use('/', function (req, res) {
res.send({"error":{"message":"unrecognized rpc"}}); res.send({"error":{"message":"unrecognized rpc"}});
}); });

View File

@ -160,6 +160,7 @@ module.exports.create = function (state) {
, protected: { , protected: {
// alg will be filled out automatically // alg will be filled out automatically
jwk: state.pub jwk: state.pub
, kid: false
, nonce: require('crypto').randomBytes(16).toString('hex') // TODO get from server , nonce: require('crypto').randomBytes(16).toString('hex') // TODO get from server
// TODO make localhost exceptional // TODO make localhost exceptional
, url: RC.resolve(reqOpts.path) , url: RC.resolve(reqOpts.path)