From 568db0ad5481475804eae3fe1cc30849b3f5a09a Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 4 Oct 2018 17:19:04 -0700 Subject: [PATCH] Fix #5: Support LDAP and DB, and pull from DB every access instead of caching in 'sessions' Signed-off-by: James Ketrenos --- server/app.js | 58 ++++++++++++++++------ server/routes/users.js | 109 ++++++++++++++++++++++++++++------------- 2 files changed, 117 insertions(+), 50 deletions(-) diff --git a/server/app.js b/server/app.js index 19702d9..a631adb 100755 --- a/server/app.js +++ b/server/app.js @@ -161,13 +161,7 @@ app.use(basePath, function(req, res, next) { html: hb.compile(templates.html)(user) }; - req.session.user = { - name: user.displayName, - mail: user.mail, - username: user.uid, - authenticated: user.authenticated, - mailVerified: user.mailVerified - }; + req.session.userId = user.id; return new Promise(function (resolve, reject) { let attempts = 10; @@ -217,25 +211,59 @@ app.use(function(err, req, res, next) { /* Everything below here requires a successful authentication */ app.use(basePath, function(req, res, next) { - if (!req.session || !req.session.user || !req.session.user.username) { + if (!req.session || !req.session.userId) { return res.status(401).send("Unauthorized"); - } + } + + if (req.session.userId == "LDAP") { + if (req.session.ldapUser) { + req.user = req.session.ldapUser; + return next(); + } + req.session.userId = null; + req.session.ldapUser = null; + return res.status(401).send("Invalid LDAP session"); + } + + let query = "SELECT uid AS username,displayName,mailVerified,authenticated,memberSince AS name,mail " + + "FROM users WHERE id=:id"; + + return userDB.sequelize.query(query, { + replacements: { + id: req.session.userId + }, + type: userDB.Sequelize.QueryTypes.SELECT, + raw: true + }).then(function(results) { + if (results.length != 1) { + return res.status(401).send("Invalid account"); + } + + req.user = results[0]; + if (!req.user.authenticated) { + return res.status(401).send("Accout not authenticated."); + } + + if (!req.user.mailVerified) { + return res.status(401).send("Account mail not verified."); + } + + if (!config.has("restrictions")) { + return next(); + } - if (config.has("restrictions")) { let allowed = config.get("restrictions"); if (!Array.isArray(allowed)) { allowed = [ allowed ]; } for (let i = 0; i < allowed.length; i++) { - if (allowed[i] == req.session.user.username) { + if (allowed[i] == req.user.username) { return next(); } } - console.log("Unauthorized (logged in) access by user: " + req.session.user.username); + console.log("Unauthorized (logged in) access by user: " + req.user.username); return res.status(401).send("Unauthorized"); - } - - return next(); + }); }); app.use(basePath, express.static(picturesPath, { index: false })); diff --git a/server/routes/users.js b/server/routes/users.js index e1b486a..070fd7c 100755 --- a/server/routes/users.js +++ b/server/routes/users.js @@ -29,12 +29,11 @@ require("../db/users").then(function(db) { }); router.get("/", function(req, res/*, next*/) { - console.log("/users"); - - if (req.session.user) { - return res.status(200).send(req.session.user); - } - return res.status(200).send({}); + console.log("/users/"); + return getSessionUser(req).then(function(user) { + req.user = user; + return res.status(200).send(req.user); + }); }); const templates = { @@ -79,6 +78,8 @@ function ldapPromise(username, password) { } router.post("/create", function(req, res) { + console.log("/users/create"); + let who = req.query.w || req.body.w || "", password = req.query.p || req.body.p || "", name = req.query.n || req.body.n || "", @@ -93,7 +94,8 @@ router.post("/create", function(req, res) { replacements: { username: mail }, - type: userDB.Sequelize.QueryTypes.SELECT + type: userDB.Sequelize.QueryTypes.SELECT, + raw: true }).then(function(results) { if (results.length != 0) { return res.status(400).send("Email address already used."); @@ -125,12 +127,15 @@ router.post("/create", function(req, res) { notes: who } }).spread(function(results, metadata) { + + req.session.userId = metadata.lastID; + return userDB.sequelize.query("INSERT INTO authentications " + "(userId,issued,key,type) VALUES " + "(:userId,CURRENT_TIMESTAMP,:key,'account-setup')", { replacements: { key: secret, - userId: metadata.lastID + userId: req.session.userId } }).catch(function(error) { console.log(error); @@ -176,19 +181,43 @@ router.post("/create", function(req, res) { send(envelope); }); }).then(function() { - req.session.user = { - name: name, - mail: mail, - username: mail, - authenticated: false, - mailVerified: false - }; - return res.status(200).send(req.session.user); + return getSessionUser(req).then(function(user) { + return res.status(200).send(user); + }); }); }); }); +const getSessionUser = function(req) { + if (!req.session.userId) { + return Promise.resolve({}); + } + + if (req.session.userId == "LDAP") { + return Promise.resolve(req.session.ldapUser); + } + + let query = "SELECT " + + "uid AS username,displayName,mailVerified,authenticated,memberSince AS name,mail " + + "FROM users WHERE id=:id"; + return userDB.sequelize.query(query, { + replacements: { + id: req.session.userId + }, + type: userDB.Sequelize.QueryTypes.SELECT, + raw: true + }).then(function(results) { + if (results.length != 1) { + return {}; + } + + return results[0]; + }); +} + router.post("/login", function(req, res) { + console.log("/users/login"); + let username = req.query.u || req.body.u || "", password = req.query.p || req.body.p || ""; @@ -199,15 +228,23 @@ router.post("/login", function(req, res) { } /* We use LDAP as the primary authenticator; if the user is not - * found there, we look them up in the site-specific user database */ + * found there, we look the user up in the site-specific user database */ return ldapPromise(username, password).then(function(user) { + user.name = user.displayName; + user.username = user.uid; + user.id = "LDAP"; + user.mail = user.mail; user.authenticated = 1; user.mailVerified = 1; + req.session.userId = "LDAP"; + req.session.ldapUser = user; return user; }).catch(function() { console.log("User not found in LDAP. Looking up in DB."); - let query = "SELECT * FROM users WHERE uid=:username AND password=:password"; + let query = "SELECT " + + "id,mailVerified,authenticated,uid AS username,displayName AS name,mail " + + "FROM users WHERE uid=:username AND password=:password"; return userDB.sequelize.query(query, { replacements: { username: username, @@ -218,40 +255,42 @@ router.post("/login", function(req, res) { if (users.length != 1) { return null; } - return users[0]; + let user = users[0]; + req.session.userId = user.id; + return user; }); }).then(function(user) { if (!user) { console.log(username + " not found (or invalid password.)"); - req.session.user = {}; + req.session.userId = null; return res.status(401).send("Invalid login credentials"); } - req.session.user = { - name: user.displayName, - mail: user.mail, - username: user.uid, - authenticated: user.authenticated, - mailVerified: user.mailVerified - }; - + let message = "Logged in as " + user.name + " (" + user.id + ")"; if (!user.mailVerified) { - console.log("Logged in as " + user.displayName + ", who is not verified email."); + console.log(message + ", who is not verified email."); } else if (!user.authenticated) { - console.log("Logged in as " + user.displayName + ", who is not authenticated."); + console.log(message + ", who is not authenticated."); } else { - console.log("Logging in as " + user.displayName); + console.log(message); } - return res.status(200).send(req.session.user); + delete user.id; + + return res.status(200).send(user); }); }); router.get("/logout", function(req, res) { - if (req.session && req.session.user) { - req.session.user = {}; + console.log("/users/logout"); + + if (req.session && req.session.userId) { + if (req.session.userId == "LDAP") { + req.session.ldapUser = null; + } + req.session.userId = null; } - res.status(200).send(req.session.user); + res.status(200).send({}); }); module.exports = router;