UNPKG

adaptorex

Version:

Connect all your live interactive storytelling devices and software

134 lines (120 loc) 4.43 kB
/** * API authentication types * * @module authentication * @copyright Lasse Marburg 2021 * @license MIT */ class Auth { constructor() { } /** * Move socket auth credentials to request object and forward to auth method * * @todo rewrite this to use cookie and/or sessionStorage and/or localStorage tokens from client instead of requiring username and password everytime * * @param {Object} socket - socket connection object * @param {function} next - call next middleware */ authenticateSocket(socket, next) { if(socket.handshake.auth) { socket.request.originalUrl = socket.handshake.url if (socket.handshake.auth.user && socket.handshake.auth.password){ log.trace(0, "socket auth with user and pw"); let user = socket.handshake.auth.user; let password = socket.handshake.auth.password; log.trace(0, "user:password",user, password, socket.request.headers); socket.request.headers.authorization = "Basic "+ Buffer.from(user + ':' + password).toString('base64') } else if (socket.handshake.auth.token){ log.trace(0, "socket auth with token", socket.handshake.auth.token); socket.request.headers.authorization = "Basic "+ socket.handshake.auth.token; } } this.authenticate(socket.request, {}, next) } } class NoAuth extends Auth{ constructor(default_user) { super() this.default_user = default_user log.info(0, "Authentication disabled") } authenticate(req, res, next) { req.user = this.default_user next() } } /** * @param {Object|Array} user - list of authorized users */ class BasicAuth extends Auth { constructor(user) { super() if(!Array.isArray(user) || (Array.isArray(user) && !user.length)) { log.warn(0, "Basic Authentication is enabled but there is no user that is authorized to connect to adaptor.") this.user = [] } else { this.user = user } log.info(0, "Basic Authentication enabled") } /** * authentication middleware function for express routing. * * respond with www-authenticate necessity. Only pass if request header contains valid authentication * * parse login and password from headers * match against users list * * Verify if login and password are set and match credentials of an existing user * * With help by this Post: https://stackoverflow.com/questions/23616371/basic-http-authentication-with-node-and-express-4/33905671#33905671 * * User example: * @example * "users": [ * { * "login": "my_user", * "password": "abcd1234" * } * ] * * @todo add Set-Cookie with Session Auth or create Session Token or similar * * @param {Object} req - request Object * @param {Object} res - response Object * @param {function} next - express next function * @returns {undefined} Returns prematurely if authentication failed and skips next request handlings */ authenticate(req, res, next) { const b64auth = (req.headers.authorization || '').split(' ')[1] || '' const [login, password] = Buffer.from(b64auth, 'base64').toString().split(':') let auth = {} if(Array.isArray(this.user)) { for(let u of this.user) { if(u.login == login) { auth = {login: u.login, password: u.password} break } } } else { auth = {login: this.user.user, password: this.user.password} } if (!login || !password || login !== auth.login || password !== auth.password) { log.warn(0, `Authentication failed for ${req.method} request to ${req.originalUrl}, user: '${login}' and pw: '${password}'. See trace log for details.`) log.trace("Request headers", req.headers) //res.set('WWW-Authenticate', 'Basic realm="401"') if(typeof res.status === "function") { res.status(401).send({name:'AuthenticationError',message:'Authentication enabled. See Readme on how to configure authentication for your adaptor server.'}) } return } req.user = auth next() } } module.exports = { BasicAuth:BasicAuth, NoAuth:NoAuth }