Hello so I have the following code in my passport.js:
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
nameField: 'fullname',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done, fullname) {
// 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, req.flash('signupMessage', 'That email is already taken.'));
} 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 = password;
newUser.local.fullname = fullname;
newUser.local.role = "default";
// save the user
newUser.save(function(err) {
if (err) {
throw err;
}
console.log(newUser);
return done(null, newUser);
});
}
});
});
}));
And I need to save the fullname into the database but unfortunately doesn't add because is the last parameter, after done. But if ill put fullname before done, the return done is is not found and gives me a application crash.
What do you think can be a solution?
You can retrieve the fullname from the req param. If you are using bodyparser then it is as simple as req.body.fullname. Use that where you need it. You need to make sure you are sending the fullname from the form with the email and password.
Local strategy for passport doesn't support other inputs than the usernameField and passwordField. If you need other inputs from the user you need to retrieve them from the original request.
Related
I want to create function which will changing password. So in first place I have to compare old password with actually user password in db. Here is the problem, I write inside router function but it is not called. Can someone help me, and tell how could I call it to get answer that old password is equall with password user?
router.post('/change-password', function (req, res, next) {
console.log(req.body)
User.comparePassword(req.body.oldPpassword, user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
You shouldn't be saving the password in the DB, that is unsafe. You should hash it in node and then save the hashed password to the DB. Then when you want to check a user, you hash the new password they gave you and compare that to the hashed one in the DB. You never, never store unhashed passwords. That is a recipe for disaster.
Libraries like bcrypt make this easy.
In a mean stack app I create a new user in User Schema then a new doc in Doc Schema
var UserSchema = new Schema({
username: String,
password: String,
docs: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Doc'
}],
)
}
var DocSchema = new Schema({…)
}
UserSchema.pre('save', function(next) {
if (this.password) {
this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
this.password = this.hashPassword(this.password);
}
next();
});
The following parts of code is the passport signup where at the end I have an issue with newUser.save(); After the push method if I do not save the user, doc ID are not displayed in user document. But saving user seems to change the hashed password also. If I comment newUser.save(); login works fine otherwise I get a wrong password
passport.use('local-signup', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true
},
function(req, username, password, done) {
process.nextTick(function() {
User.findOne({
username: username
}, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'Username is already taken.'));
} else {
var newUser = new User();
newUser.username = username;
newUser.password = password;
newUser.email = req.body.email;
newUser.save(function(err) {
if (err)
throw err;
var doc = new Doc({
user: newUser.username,
docTitle: newUser.username
});
doc.save(function(err) { // create doc
if (err) {
return next(err);
} else {
newUser.docs.push(doc); // push doc'id in docs field in user
newUser.save(); // save user after doc'id has been push
};
return done(null, newUser);
});
});
Any help would be appreciated
Your logic in your mongoose pre save middleware says 'if there is a password on the document being saved, generate a salt and hash the password'. Therefore, if a password exists on the document that has already been salted and hashed, when the middleware runs it will salt and hash this pre-existing password again. This is why you can't login a second time; your password is changing every time you save the document.
I'm guessing you expect the mongoose pre save middleware to run only when you save the document the first time. The pre save middleware runs every time you save the document. There is a this.isNew property available on the document in the pre save middleware that you can make use of. This will ensure the password is only generated the first time you save the document.
UserSchema.pre('save', function(next) {
if (this.password && this.isNew) {
this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
this.password = this.hashPassword(this.password);
}
next();
});
I am creating a user login. I am able to have the user sign up and when the user sings up his password is encrypted before it is saved in the database.
When that same user tries to log in, I am getting an "invalid password".
This is because it is comparing the user input to an encrypted password in the database. Example if password is 1234, then in database it is saved as "$2a$104$0301". When the user tries to log in, the user input which is "1234" is compared to "2a$104$0301". How would I fix?
Here is my code for login:
var LocalStrategy = require('passport-local').Strategy;
var User = require('../Models/users.js');
var bcrypt = require('bcrypt-nodejs');
module.exports = function(passport){
passport.use('login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done){
User.findOne({'username' : username},
function(err, user){
if(err)
return done(err);
if(!user){
console.log('User Not Found with username: '+username);
return done(null, false,
req.flash('message', 'User Not Found.'));
}
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done (null, false,
req.flash('message', 'Invalid Password'));
}
return done(null, user);
}
);
})
);
var isValidPassword = function(user, password){
var result = bcrypt.compareSync(password, user.password);
if (result) {
console.log("Password correct");
} else {
console.log("Password wrong");
}
return result;
}
}
compareSync method takes only 2 arguments and returns a boolean value true or false.
You should perform the check like this:
var result = bcrypt.compareSync(password, user.password);
if (result) {
console.log("Password correct");
} else {
console.log("Password wrong");
}
Really late to the party, however I just had this same problem and the reason it wasn't working for me was that I had encrypted the input password before trying to compare with the already encrypted 'user.password'.
Once I realised there was no need to encrypt the input password, the compareSync worked perfectly.
From bcrypt - npm:
To check a password:
// Load hash from your password DB.
bcrypt.compareSync(myPlaintextPassword, hash); // true
bcrypt.compareSync(someOtherPlaintextPassword, hash); // false
The "compareSync" function counters timing attacks (using a so-called 'constant-time' algorithm). In general, don't use the normal JavaScript string comparison functions to compare passwords, cryptographic keys, or cryptographic hashes if they are relevant to security.
I had a similar problem, when executing bcrypt.compareSync, it did not hash the password of the user who was without bcrypt, the problem was the order in which I had them, which was the following:
bcrypt.compareSync (passwordHash, password)
I solved it by organizing it, first the password and then the passwordHash, which would look like this:
bcrypt.compareSync (password, student.password)
I hope it helps someone, good code! <3 #sebasrestrepom
I've asked a similar question before, but I noticed it was in the Javascript section.
I have more specific ideas of what might be going wrong now, as well.
Basically, req.session.passport is empty in my logs. Whenever I start navigating around my site, req.user becomes undefined because the session doesn't have Passport's logged in user anymore.
I would like to know if anyone knows how to solve this? Maybe it's just an error in the configuration of Passport, or the entire Express setup?
App.js:
var express = require("express"),
bodyParser = require("body-parser"),
mongodb = require("mongodb"),
mongoose = require("mongoose"),
uriUtil = require("mongodb-uri"),
morgan = require("morgan"),
session = require("express-session"),
passport = require("passport"),
flash = require("connect-flash"),
ip = "hidden",
port = process.env.PORT || 80
var app = express()
app.disable("x-powered-by")
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(morgan("dev")); // log every request to the console
// required for passport
app.use(session({
secret: "hidden",
key: 'asdasdasd',
cookie: { maxAge: 60000, secure: false },
resave: true,
saveUninitialized: false
})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.set("view engine", "jade")
app.use(express.static(__dirname + "/views"))
require("./includes/passport")(passport)
require("./includes/subject")
require("./includes/user")
Passport.js:
var LocalStrategy = require("passport-local").Strategy,
User = require("./user"),
bCrypt = require('bcrypt-nodejs')
module.exports = function(passport) {
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user._id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// 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('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) {
// 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({ "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, req.flash("message", "Dit e-mail-adres is al bezet"));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.email = email;
newUser.password = createHash(password);
newUser.firstname = req.param('firstname');
newUser.lastname = req.param('surname');
newUser.year = parseInt(req.param('year'));
newUser.study = req.param('study');
newUser.courses = req.param('courses');
newUser.phone = req.param('phone');
newUser.availability = req.param('availability');
newUser.description = req.param('descText');
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
// 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("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.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 with email ' + email)
return done(null, false, req.flash('message', 'Gebruiker niet gevonden')); // req.flash is the way to set flashdata using connect-flash
}
if (!isValidPassword(user, password)){
console.log('Incorrect Password');
return done(null, false, req.flash('message', 'Onjuist wachtwoord')); // redirect back to login page
}
// all is well, return successful user
return done(null, user);
});
}));
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
}
// Generates hash using bCrypt
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
}
};
The routes:
api.post("/signup", passport.authenticate("signup", {
successRedirect: "/profile",
failureRedirect: "/",
failureFlash: true
}))
api.post("/login", passport.authenticate("login", {
successRedirect: "/profile",
failureRedirect: "/login"//,
failureFlash: true
}))
router.get("/", function(req, res) {
// serve index.html
res.render("index", {
title: 'Home',
user: req.user,
message: req.flash("message")
})
})
It works on the page that is accessed directly after logging in, which I control as follows:
router.get("/profile", isLoggedIn, function(req, res) {
res.render("profile", {
title: 'Gebruikersprofiel van ' + req.user.firstname + " " + req.user.lastname,
user: req.user // get the user out of session and pass to template
})
})
function isLoggedIn(req, res, next) {
console.log(req.session)
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next()
// if they aren't redirect them to the home page
res.redirect("/login")
}
So far, I've tried adding middleware to add req.user to req.session, and doing the same thing in the login POST. Also I've tried changing the order in which I initialize the middleware in app.js. I am using the new express-session version, without CookieParser, as I read that CookieParser is no longer needed.
If anyone can help me in any way, it would be much appreciated! I've been stuck for a while (as have others).
The problem was not anything I did wrong in setting up the session, or Passport in general, but rather in my links.
I read somewhere that someone was accidentally working in multiple domains (his platform was apparently multi-server), and that made me look through my links this morning.
Apparently, I was linking to my website with www. prefixed, but the session was initialized where there was no www. in front of the URL. I saw this in the cookies.
The solution was, therefore, to link through the website consistently, either having www. prefixed everywhere or nowhere.
i would like to test this method using mocha and i don't know where to start ?
the route :
app.post('/signup', passport.authenticate('local-signup', {
failureRedirect: '/#/',
failureFlash: true
}),
function(req, res) {
res.jsonp(req.user);
});
and here is the definition of my service :
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
pseudoField: 'pseudo',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, pseudo, done) {
// 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) {
console.log('That email is already taken');
//var newUser = new User();
return done(404, null);
// return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
console.log('creation new user');
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.local.pseudo = pseudo;
console.log(pseudo);
console.log(newUser.local);
// save the user
console.log('going to save in bdd');
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
i just need some help to know how i could test this methode and how to call it.