Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express-mysql-session preventing passport deserializeUser from running

I have an app using passport.js to log in users through facebook, and am attempting to use express-mysql-session to persist their login states. If I don't include the express-mysql-session code, the passport serializeUser and deserializeUser functions hit fine...however when I un-comment the code that attempts to store their session with express-mysql-session, the deserializeUser function doesn't get hit, and the user never gets properly logged in.

server.js file

var express      = require('express'); var mysql        = require('mysql'); var passport     = require('passport'); var session      = require('express-session'); var MySQLStore   = require('express-mysql-session')(session);  if (typeof process.env.OPENSHIFT_MYSQL_DB_HOST === "undefined"){     var options = {         host     : 'localhost',         port     : '3307',         user     : 'user',         password : 'password',         database : 'database',         socketpath: '/var/run/mysqld/mysqld.sock'     } } else {      var options = {         host     : process.env.OPENSHIFT_MYSQL_DB_HOST,         port     : process.env.OPENSHIFT_MYSQL_DB_PORT,         user     : process.env.OPENSHIFT_MYSQL_DB_USERNAME,         password : process.env.OPENSHIFT_MYSQL_DB_PASSWORD,         database : process.env.OPENSHIFT_APP_NAME,         socket   : process.env.OPENSHIFT_MYSQL_DB_SOCKET     } };      var connection = mysql.createConnection(options);  var sessionStore = new MySQLStore({     checkExpirationInterval: 900000,// How frequently expired sessions will be cleared; milliseconds.     expiration: 86400000,// The maximum age of a valid session; milliseconds.     createDatabaseTable: false,// Whether or not to create the sessions database table, if one does not already exist.     connectionLimit: 1,     schema: {         tableName: 'LoginRequests',         columnNames: {             session_id: 'loginID',             expires: 'expires',             data:'data'         }     } }, connection);   self.initializeServer = function() {         self.app = module.exports = express();         self.app.configure(function() {             self.app.set('views', __dirname + '/public');             self.app.set('view engine', 'html');             self.app.engine('html', require('hogan-express'));             self.app.enable('view cache');             self.app.use(express.favicon());             self.app.use(express.logger('dev'));             self.app.use(express.bodyParser());             self.app.use(express.methodOverride());             self.app.use(express.cookieParser('secret'));             self.app.use(session({                 key: 'session_cookie_name',                 secret: 'secret',                 cookie: {maxAge: 3600000, secure:false},                 store: sessionStore,                 resave: false,                 saveUninitialized: false             }));             // required for passport             self.app.use(passport.initialize());             self.app.use(passport.session()); // persistent login sessions             self.app.use(express.static(path.join(__dirname, 'public')));             self.app.use('/public',express.static(__dirname, '/public'));             self.app.use(self.app.router);             //self.app.use(require('stylus').middleware(__dirname + '/public'));           });      require('./routes/site.js');       require('./config/passport.js')(passport); // pass passport for configuration       } 

So, if I comment out the "store" option in the session object above, the passport functions get hit. If I leave this line un-commented, the deserializeUser function does not get hit.

Passport functions

passport.serializeUser(function(user, done) {         console.log('you have been serialized!');             done(null, user.id);     });       // used to deserialize the user     passport.deserializeUser(function(id, done) {         console.log('you have been deserialized!');         connection.query("SELECT * FROM Users WHERE id = "+id,function(err,rows){             done(err, rows[0]);         });     }); 

EDIT

Mor Paz suggested that I include some of the logs from when I run my server with the debug module. Below are the logs right before, and immediately after the user is serialized. The user should be deserialized at some point near this, but never is.

GET /auth/facebook 302 81ms - 412b express-mysql-session:log Getting session: oNcJ4UapxCY_zKOyfSBTUWaVhaNZuFRq +356ms you are a user! you have been serialized!   express-mysql-session:log Setting session: tgRPY-Mb1VDP2zaSMOFhlf_IWFhVpTia +798ms   express-mysql-session:log Getting session: tgRPY-Mb1VDP2zaSMOFhlf_IWFhVpTia +6ms GET /auth/facebook/callback?    code=AQCWPvA5ZRMYoTueW6_wWU49Up5ggjW68ufOtiYkU5IzhRjSNyyWnzlQVprgQo_uubQkEVvNI0yo53ET3cWBnDAHUGmAXPBy_ITEmC-biE2KEGEr0iCm_cqjuG90nnePY-k9U2oFUbX2kvLgMeM0kZ-094EHiU_NJjmAJNj6mzTkSE47935RhJy0Tba_sYS88_C0N3kn5f5kcoTC4KsgW1gBHWWJAwZ68Lj94ffVe2hN97580CtzEpJa0wwQHwTBYfmjQ0NfUdx07m4rXW9R7PR06aHDcUDrYqR9Kb0LWq4sZLbQjV5rI7gzkWG-huhq7IY 302 825ms - 72b   express-mysql-session:log Setting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +56ms   express-mysql-session:log Getting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +23ms   express-mysql-session:log Getting session: Xo9OjfmJzTFp1CSF6srLi_UyxTCLg-EI +2ms GET /profile 200 84ms - 4.22kb 
like image 902
user2796352 Avatar asked Sep 28 '16 23:09

user2796352


1 Answers

It was impossible to replicate the problem, so I prepared a working example. [Github repo.]

Its crafted for Openshift, since I saw the usage of its environment variables (it can be adapted with ease for other use cases).

I did some modifications to the original concept :

  1. Replaced the old, deprecated (express) bundled middleware usages.
  2. Using a Class instead of the self = this concept
  3. Using Github instead of Facebook for the user login...
  4. Included some basic functions to include new users to the db
  5. Missing some original modules (can be included with ease)

I hope it can be useful as a starting point.

 // .: DB Configuration :. const mysql = require('mysql');  var dbconf = {host:process.env.OPENSHIFT_MYSQL_DB_HOST,port:process.env.OPENSHIFT_MYSQL_DB_PORT,user:process.env.OPENSHIFT_MYSQL_DB_USERNAME,password:process.env.OPENSHIFT_MYSQL_DB_PASSWORD,database:process.env.OPENSHIFT_APP_NAME,socket:process.env.OPENSHIFT_MYSQL_DB_SOCKET}}     const dbconn = mysql.createConnection(dbconf); /*or create a pool*/ dbconn.connect(); // .: Express & Other Middleware Modules :. var express = require('express'); var path = require('path'); var bodyParser = require('body-parser'); var methodOverride = require('method-override'); var cookieParser = require('cookie-parser'); var serveStatic = require('serve-static'); // .: Sessions :. var passport = require('passport'); var GitHubStrategy = require('passport-github2'); var session = require('express-session'); var MySQLStore = require('express-mysql-session')(session); var sessionStoreConf = {   connectionLimit:1,checkExpirationInterval:900000,expiration:86400000,   createDatabaseTable:true,schema:{tableName:'LoginRequests',columnNames:{session_id:'loginID',expires:'expires',data:'data'}} }; var sessionStore = new MySQLStore(sessionStoreConf,dbconn); // .: Server (class) :. class Server {   constructor(port, ip){     this.app = express();     this.app.use(cookieParser('secret'));     this.app.use(session({       key:'session_cookie_name',       secret:'secret',       cookie:{maxAge:3600000,secure:false},       store: sessionStore,       resave:false,       saveUninitialized:false     }));     this.app.use(passport.initialize());     this.app.use(passport.session());     this.app.use(serveStatic(path.join(__dirname,'public')))     this.app.listen(port,ip,function(){console.log('[i] Application worker started.');});     //require('./routes/site.js'); //~Example (routes/site.js) :       this.app.get("/",function(req,res){res.send("<a href='./auth/github'>Click here to login (GitHub)</a>");})       this.app.get('/auth/github',passport.authenticate('github',{scope:['user:email']}));       this.app.get('/auth/github/callback',passport.authenticate('github',{failureRedirect:'/'}),function(req,res){res.redirect('/success');});       // route for valid logins       this.app.get('/success', function(req, res){          if(req.user){ console.log(req.user);  res.send(req.user); }         else{ res.redirect('/login'); }       });       // route to check the sessionStore table entries in the browser       this.app.get('/sessions',function(req,res){         dbconn.query("SELECT * FROM LoginRequests",function(err,rows){           if(err){console.log(err);}else{             if(rows.length!=0){               res.send(JSON.stringify(rows));               console.log(rows);             }else{res.send("No LoginRequests found");}           }         });       });     //require('./config/passport.js')(passport);  //~Example (config/passport.js) :       passport.use(new GitHubStrategy(         {clientID:"clientID",clientSecret:"clientSecret",callbackURL:"callbackURL"},         function(token, tokenSecret, user, cb){CheckUser('github',user,cb);}       ));     } } const server = new Server(process.env.OPENSHIFT_NODEJS_PORT,process.env.OPENSHIFT_NODEJS_IP); // .: Passport : Serialize & Deserialize User :. passport.serializeUser(function(user, done){  console.log('[passport] serializeUser');  done(null,user.id); }); passport.deserializeUser(function(id, done) {  console.log('[passport] deserializeUser');   dbconn.query("SELECT * FROM Users WHERE id=?",[id],function(err,rows){   if(err){console.log(err);}else{     if(rows.length!=0){ done(err,rows[0]); }     else{ done(err,null); }   }  }); });  //:Check if user exists: function CheckUser(platform,user,cb){   dbconn.query("SELECT * FROM Users WHERE id=?",[user.id],function(err,rows){   if(err){console.log(err); cb(err,null);}else{     if(rows.length!=0){cb(null,user);}     else{CreateUser(platform,user,cb);}     }   }); }   //:Create new user: function CreateUser(platform,user,cb){   switch(platform){     case "github":        var newUserObj  = {id:user.id,platform:platform,email:user.emails[0].value};       dbconn.query("INSERT INTO Users SET ?",newUserObj,function(err){         if(err){console.log(err); cb(err,null);}else{cb(null,user);}       });     break;     default: console.log("[error] (createUser) : platform not implemented :",platform); cb(err,null); break;   } } 
like image 196
EMX Avatar answered Sep 24 '22 17:09

EMX