Improved websocket auth when 2nd factor is used.

Ylian Saint-Hilaire committed Mar 21, 2019 at 11:45 UTC e8356b0dae859aaa7a33773e7fae94802d70ecc2
1 file changed +64 -4
webserver.js
+64 -4
@@ -2507,9 +2507,26 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2507 if ((req.query.user != null) && (req.query.pass != null)) {
2508 // A user/pass is provided in URL arguments
2509 obj.authenticate(req.query.user, req.query.pass, domain, function (err, userid) {
2510 - if ((err == null) && (obj.users[userid])) {
2511 - // We are authenticated
2512 - func(ws, req, domain, obj.users[userid]);
2510 + var user = obj.users[userid];
2511 + if ((err == null) && (user)) {
2512 + // Check if a 2nd factor is needed
2513 + if (checkUserOneTimePasswordRequired(domain, user) == true) {
2514 + if (req.query.token) {
2515 + try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired' })); ws.close(); } catch (e) { }
2516 + } else {
2517 + checkUserOneTimePassword(req, domain, user, req.query.token, null, function (result) {
2518 + if (result == false) {
2519 + try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired' })); ws.close(); } catch (e) { }
2520 + } else {
2521 + // We are authenticated with 2nd factor.
2522 + func(ws, req, domain, user);
2523 + }
2524 + });
2525 + }
2526 + } else {
2527 + // We are authenticated
2528 + func(ws, req, domain, user);
2529 + }
2530 } else {
2531 // Failed to authenticate, see if a default user is active
2532 if (obj.args.user && obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]) {
@@ -2529,12 +2546,55 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2546 if ((cookie != null) && (obj.users[cookie.userid]) && (cookie.domainid == domain.id)) {
2547 // Valid cookie, we are authenticated
2548 func(ws, req, domain, obj.users[cookie.userid], cookie);
2532 - return;
2549 } else {
2550 // This is a bad cookie, keep going anyway, maybe we have a active session that will save us.
2551 Debug(1, 'ERR: Websocket bad cookie auth: ' + req.query.auth);
2552 + try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { }
2553 }
2554 + return;
2555 + } else if (req.headers['x-meshauth'] != null) {
2556 + // This is authentication using a custom HTTP header
2557 + var s = req.headers['x-meshauth'].split(',');
2558 + for (var i in s) { s[i] = Buffer.from(s[i], 'base64').toString(); }
2559 + if ((s.length < 2) || (s.length > 3)) { try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { } return; }
2560 + obj.authenticate(s[0], s[1], domain, function (err, userid) {
2561 + var user = obj.users[userid];
2562 + if ((err == null) && (user)) {
2563 + // Check if a 2nd factor is needed
2564 + if (checkUserOneTimePasswordRequired(domain, user) == true) {
2565 + if (s.length != 3) {
2566 + try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired' })); ws.close(); } catch (e) { }
2567 + } else {
2568 + checkUserOneTimePassword(req, domain, user, s[2], null, function (result) {
2569 + if (result == false) {
2570 + try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'tokenrequired' })); ws.close(); } catch (e) { }
2571 + } else {
2572 + // We are authenticated with 2nd factor.
2573 + func(ws, req, domain, user);
2574 + }
2575 + });
2576 + }
2577 + } else {
2578 + // We are authenticated
2579 + func(ws, req, domain, user);
2580 + }
2581 + } else {
2582 + // Failed to authenticate, see if a default user is active
2583 + if (obj.args.user && obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]) {
2584 + // A default user is active
2585 + func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]);
2586 + } else {
2587 + // If not authenticated, close the websocket connection
2588 + Debug(1, 'ERR: Websocket bad user/pass auth');
2589 + try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { }
2590 + }
2591 + }
2592 + });
2593 + return;
2594 }
2595 +
2596 + //console.log(req.headers['x-meshauth']);
2597 +
2598 if (obj.args.user && obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]) {
2599 // A default user is active
2600 func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]);