I am using passport with passport-local-mongoose for register and login users.
This is the code I use to login users:
passport.use(new localStrategy({ usernameField: 'email' }, function(email, password, done) {
User.findOne({ email: email }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username or password.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect username or password.' });
}
return done(null, user);
});
}));
Everything works fun but user.validPassword.
I define it in user model:
userSchema.methods.validPassword = function(password) {
// What should I write here?
};
Since hash password will be saved into database I do not know how to validate password.
For example this is one user saved into database{
"_id" : ObjectId("5901d55c30967512407cdcd0"),
"salt" : "7e76e1de50856c0a0e219c48609e0c86e8036bd4aa48e5161635f88dd19b695b",
"hash" : "eb78dcb7109454457b0709b6b49f322c69454930e3a6ca90621b1f38d4a068c46a34d0af8ba4f3cb3c3f9c8a30889f54028f182e1a038ab5d642e408117a93b34a519e594f62ea2209ef350f17d388e07476c021fdd66979e5752305b2f41571c830c4e03300cfbddce70443debee06d921900e1f7b9f024ea8d875553f01989e9267b01cc7e9da70f5ee39085527a55c8b6a9f5c7f21e07166797d5446322f52ec79c8e6bfd3e31d5f3953d86a13775da09f7ac3a5a85e5342cd35324bc66055030ca738fa657c50ec4368fe1fd4a26448b460996dc85ddebf90f92796f2b1adf9b905e0590efcadd8326053e354afcc144a155ca7ba1a0f1269cd2c5edec9ef4c643e5ca58310bf3283ed21bb94da6b22c113d19baf091f62bf1776fdcd4bca572cc114ec991d780c18524aad34988d0045f9a1d35e6cda4a6be337d7c8dce8256a240ecac9c7f4ac6c231a3c258f3660b5dd6daf4e67f878fbd9af9e52f9d36266828f564e6ac86f3aed98f7af0bb39017f6080e41cb49237bec6eae77253200750be14e53e79e3fc8d29a3a5cc774905e47bc8df6e5ae9f1b38d9ef738a7cc7890aba4bbea757c694df5faaeed2c692adcc9d8bb0242a5ced98c6a015f5b0b3b475b4a78767a1e9e3c6c9f1bc1be42a835f9e54de3ce223f6190ed457ea972ee4be6f506fd3995411d05247b7102c396c3a16b0d4c26664833d2224191cc",
"username" : "stve45",
"email" : "stebe#companycom",
"name" : "Steve",
"__v" : 0
}
I also use simple passport-local-authenticate.
Any help will be appreciate, thanks a lot.
If you are using passport-local-mongoose, it will create a salt and hash itself by taking your password. So that's why in your user schema you don't have to save the password field.
But the local strategy for passport-local-mongoose is quite different from normal passport local strategy. It is like
passport.use(new LocalStrategy(User.authenticate()));
This will check the entered password and will check it with the salt and hash.
The code you wrote is for normal local strategy. That should not use if you are using passport-local-mongoose.
This is how you should srialize and desirialize passport-local-mongoose:
passport.serializeUser(User.serializeUser());passport.deserializeUser(User.deserializeUser());
I assume you have a method for generating the salt and hash before saving.
In your validPassword method, you call the same method and compare the result from the user's password inout and compare it to what you have in the DB/ If it matches, then you are good.
As an alternative, there are libraries to manage this. I use bcrypt. See a sample here:
adminSchema.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) {
return next();
}
// password changed so we need to hash it (generate a salt)
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) {
return next(err);
}else{
// hash the password using our new salt
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) { return next(err); }
// override the cleartext password with the hashed one
user.password = hash;
next();
});
}
});
});
adminSchema.methods.comparePassword = function(password, cb) {
console.log('comparing password');
bcrypt.compare(password, this.password, function(err, isMatch) {
cb(err, isMatch);
});
};
Here is an example code.Please note that the User.findOne() function is far from being complete.It's there just for you to see where this code stands with respect to yours and to give you an idea of what changes should be made.
passport.use('local.signup', new LocalStrategy({
usernameField:'email', //it can be email or whatever one chooses
passwordField:'password',
confirmField:'password',
passReqToCallback:true//here is the trick.u pass everything you want to do to a callback
},function (req,email, password, done) {
req.checkBody('email','Invalid e-mail address...').notEmpty().isEmail().normalizeEmail();//validate email
req.checkBody('password','Invalid password...').notEmpty().isLength({min:8});//validate pass to be min 8 chars but you can provide it with checking for capital letters and so on and so forth
var errors = req.validationErrors();
if(errors){
var messages = [];
errors.forEach(function (error) {
messages.push(error.msg)
});
return done(null, false, req.flash('error', messages))
}
User.findOne({ email: req.body.email }, function (err, user) {
// Make sure user doesn't already exist
if (user) return done(null, false, {message:'The email address you have
entered is already associated with another account.'
});
Related
So I am trying to create a signup/login logic for my website using passport and bcrypt-nodejs for password hashing. I am successful at registering a user, but then on login I always get into the 'false' branch for password authentication and am getting my console message for 'Wrong Password' Here is my login passport code:
passport.use('user-local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'email' : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user) {
console.log('No user found.');
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
}
bcrypt.compare(password, user.password, function(err, res) {
if (err)
throw err;
if(!res) {
console.log('Ooops!. Wrong Pass!');
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
}
return done(null, user);
});
});
}));
And here is my signup logic
passport.use('user-local-signup', new LocalStrategy({
usernameField : 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function (req, email, password, done) {
// asynch
// User.findOne will not fire unless data is sent back
process.nextTick(function() {
User.findOne({'email' : email}, function (err, user) {
if(err)
return done(err);
if(user) {
console.log('That email is already taken');
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// checks for password and repeat_password match
if (password != req.body.repeat_password) {
console.log('Passwords do not match.');
return done(null, false, req.flash('signupMessage', 'Passwords do not match.'));
}
var newUser = new User();
newUser.email = email;
bcrypt.hash(password, null, null, function(err,hash){
if (err)
throw err;
else {
newUser.password = hash;
}
});
newUser.save(function(err) {
if(err)
throw err;
return done(null, newUser);
});
console.log('New user was created: ' + email);
}
});
});
}));
I have mongoose schema like so
var mongoose = require ('mongoose');
var bcrypt = require('bcryptjs');
var Schema = mongoose.Schema;
var SALT_WORK_FACTOR = 10;
var touristSchema = new Schema ({
local: {
email: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String,
}
});
touristSchema.pre('save', function(next) {
var user = this;
console.log('bcrypt called by strategy', user);
// if user is facebook user skip the pasword thing.
if (user.facebook.token) {
next();
}
// only hash the password if it has been modified (or is new)
if (!user.isModified('password') && !user.isNew){
console.log('I am in here', user.isNew);
return next();
}
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
console.log('I am in genSalt');
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.local.password, salt, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.local.password = hash;
next();
});
});
});
touristSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.local.password, function(err, isMatch) {
// console.log(this.local.password);
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('users', touristSchema);
and login strategy like this
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(req, email, password, done) {
process.nextTick(function() {
User.findOne({ 'local.email': email }, function(err, user) {
if(err)
return done(err);
if(!user)
return done(null, false, req.flash('loginMessage', 'No User Found'));
user.comparePassword(password, function(err, isMatch) {
if (err) throw err;
if (isMatch) {
done(null, user);
}
else
done(null, false, req.flash('loginMessage', 'Incorrect password'));
});
});
});
}
));
everything is working as expected but when I try to log in it gives me error:
TypeError: Cannot read property 'password' of undefined.
Turns out that this.local is undefined.
This is very strange as in touristSchema.pre hook we assigned var user = this and on logging this returned user document. When in compare method we are using touristSchema.methods.compare then this should must refer to the document as written in mongoose middleware docs too. I am beating my head over it for a couple of days now and have consumed every available help I could. Any help is greatly appreciated in advance. Thanks
and yes my
mongnodb version is v3.2.15
mongoose version is 4.9.7
which looks compatible to me according to mongoose docs
I have a user table in which i have an Admin account and some other normal users accounts.
I want to do all activities which for a particular user. It should act like that activity done by same user.
Can somebody tell me how can i switch to another account from Admin account
without login to that account.
Currently i use passport authentication.(passport-local)
Here is my code
app.get('/secure/group/login', function(req,res,next) {
passport.authenticate('local',function(err,user,info) {
console.log("error is "+err);
req.logIn('tessAccount',function(err) {
console.log("Weer" +err);
});
console.log("dd");
})(req,res,next);
});
});
and passport code
var LocalStrategy = require('passport-local').Strategy;
module.exports = function(passport) {
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.token);
});
passport.use(new BearerStrategy(
function(token, done) {
user.tokenExist(token, function(err, user) {
if (err) {
return done(err);
}
else {
return done(null, user, { scope: 'all' });
}
});
}
));
// used to deserialize the user
passport.deserializeUser(function(accessToken, done) {
user.getUserByAccessToken(accessToken, function(err, dbUser) {
if (err) {
done(err);
} else {
done(null, dbUser[0]);
}
});
});
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
user.emailExists(email, function(err, exists) {
if (err)
return done(err);
else if (exists) {
return done(null, false, {
message: req.flash('loginMessage')
});
} else {
req.userDetails.status = 0;
req.userDetails.token = md5.digest_s(req.userDetails.email + new Date());
req.userDetails.userImage = config.user.image;
user.register(req.userDetails, function(err, newUser) {
if (err)
return done(err);
else {
/*Get user Shared article if exist start*/
getSharedArticlesOfnewlyuserIfExist(email, newUser.insertId);
/*Get user Shared article if exist end*/
req.userDetails.id = newUser.insertId;
return done(err, req.userDetails);
}
});
}
});
}));
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
user.matchPassword({
email: email,
password: password
}, function(err, newUser) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (newUser.length > 0) {
var user = {
id: newUser[0].user_id,
email: newUser[0].email_id,
token: newUser[0].user_access_token
};
return done(null, user);
} else {
return done(null, false, {
message: 'Incorrect username or password.'
}); // req.flash is the way to set flashdata using connect-flash
}
});
}));
User.findOne({ username: 'Myusername' }, function(err, user) {
req.logIn(user, function(err){});
});
This worked for me to log into an account without using password, it switches from my admin account to an user account.
Actually I'm using passport.js and mongoose
I'm looking at PassportJS for authentication and have a login form with username and password. But if I look at the documentation, I see that the password is passed in clear text. Which means if anyone does a console.log(password), the password will be visible. How do I ensure the password submitted by login form is encrypted?
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
1) From the client to server
Use SSL.
2) From the server to disk / database
When creating the password, hash it first and save the hash to disk.
Later, when validating a user, compare the hash of the submitted password against the hash on disk.
From the passport-local examples it would look something like this if using bcrypt:
// Bcrypt middleware
userSchema.pre('save', function(next) {
var user = this;
if(!user.isModified('password')) return next();
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if(err) return next(err);
bcrypt.hash(user.password, salt, function(err, hash) {
if(err) return next(err);
user.password = hash;
next();
});
});
});
// Password verification
userSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if(err) return cb(err);
cb(null, isMatch);
});
};
Note: you'll need to use bcrypt or some other encryption module in addition to passport-local...but that's not super complicated and the example from the passport-local repo provides pretty much all you'll need to get started.
I'm new to node express and passport so I'm not sure what I'm missing. I'm trying to use a custom callback as all I want is a json response from my registration strategy. Currently I keep getting the following error "Missing credentials". I've been at it for a while now and I'm stuck.
Here is my controller:
app.post('/services/authentication/registration', function(req, res, next) {
console.log('before authentication')
passport.authenticate('local-registration', function(err, user, info) {
console.log('authentication callback');
if (err) { return res.send({'status':'err','message':err.message});}
if (!user) { return res.send({'status':'err','message':info.message});}
if (user!=false) { return res.send({'message':'registration successful'});}
})(req, res, next);
},
function(err, req, res, next) {
return res.send({'status':'err','message':err.message});
});
And my passport strategy:
passport.use('local-registration', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
console.log('credentials passed to passport' + email + '' + password)
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, {message: 'User already exists'});
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
I dont think you should send "req" as a parameter to the authentication function. take a look at this example from the passport docs:
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));