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: {
// alg will be filled out automatically
jwk: state.pub
, kid: false
, nonce: nonce
, url: newAccountUrl
}

View File

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

View File

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