WIP: switch to authenticated requests
This commit is contained in:
parent
8b2e6e69d0
commit
1826ec8497
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"}});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue