Add authentication middleware.

The user is authenticated by one of the following
methods, in order of priority:

* The presence of a valid JWT.
* Its IP.
* Its hostname.

In the case of the latter two methods, if authentication
is successful a JWT valid for 15 minutes will be generated
and passed back to the user in a cookie.
This commit is contained in:
D. Berge
2020-10-11 13:11:43 +02:00
parent e0cd52f21a
commit a3bfb73937
6 changed files with 94 additions and 1 deletions

View File

@@ -0,0 +1,61 @@
const dns = require('dns');
const { Netmask } = require('netmask');
const cfg = require('../../../lib/config');
const jwt = require('../../../lib/jwt');
async function authorisedIP (req, res) {
const validIPs = cfg.global.login.ip;
for (const key in validIPs) {
const block = new Netmask(key);
if (block.contains(req.ip)) {
const payload = Object.assign({
ip: req.ip,
autologin: true
}, validIPs[key]);
jwt.issue(payload, req, res);
}
}
return Promise.resolve(true);
}
async function authorisedHost (req, res) {
const validHosts = cfg.global.login.host
for (const key in validHosts) {
const ip = await dns.promises.resolve(key);
if (ip == req.ip) {
const payload = Object.assign({
ip: req.ip,
host: key,
autologin: true
});
jwt.issue(payload, req, res);
}
}
return true;
}
async function auth (req, res, next) {
// Check for a valid JWT (already decoded by a previous
// middleware).
if (req.user) {
next();
return;
}
// Check if the IP is known to us
if (await authorisedIP(req, res)) {
next();
return;
}
// Check if the hostname is known to us
if (await authorisedHost(req, res)) {
next();
return;
}
next({status: 401, message: "Not authorised"});
}
module.exports = auth;

View File

@@ -1,3 +1,4 @@
exports.jwt = require('./jwt');
// exports.access = require('./access');
exports.authentify = require('./authentify');

View File

@@ -24,7 +24,10 @@ try {
config = {
"jwt": {
secret
secret,
options: {
expiresIn: 15*60*1000
}
},
"db": {
"user": "postgres",

22
lib/www/server/lib/jwt.js Normal file
View File

@@ -0,0 +1,22 @@
const jwt = require('jsonwebtoken');
const cfg = require('./config');
function issue (payload, req, res) {
console.log("ISSUE", payload, cfg.jwt);
const token = jwt.sign(payload, cfg.jwt.secret, cfg.jwt.options);
if (req) {
req.user = payload;
}
if (res) {
res.cookie("JWT", token, {maxAge: cfg.jwt.options.expiresIn || 0});
}
return token;
}
module.exports = {
issue
};

View File

@@ -366,6 +366,11 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"netmask": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz",
"integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU="
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",

View File

@@ -13,6 +13,7 @@
"express": "^4.17.1",
"express-jwt": "^6.0.0",
"jsonwebtoken": "^8.5.1",
"netmask": "^1.0.6",
"node-fetch": "^2.6.1",
"pg": "^8.3.3",
"ws": "^7.3.1",