Mongo create user error using passport authentication - node.js

I am using MEAN.IO stack (default template with Mongoose) and Passport.js authentication to create new users. Whenever user.save(...) is called in the below code:
// Use Facebook strategy
passport.use(new FacebookStrategy({
clientID: config.strategies.facebook.clientID,
clientSecret: config.strategies.facebook.clientSecret,
callbackURL: config.strategies.facebook.callbackURL
},
function(accessToken, refreshToken, profile, done) {
User.findOne({
'facebook.id': profile.id
}, function(err, user) {
if (user) {
return done(err, user);
}
user = new User({
name: profile.displayName,
email: profile.emails[0].value,
provider: 'facebook',
facebook: profile._json,
roles: ['authenticated']
});
user.save(function(err) {
if (err) {
console.log(err);
return done(null, false, {message: 'facebook login failed, email already used by other login strategy'});
} else {
return done(err, user);
}
});
});
}
));
The console logs the following error:
MongoError: attempt to use unsupported textIndexVersion 2, only textIndexVersion 1 supported
I've looked online and through the MEAN.IO stack code and can't find anything about how to change the textIndexVersion.
Any ideas how to change the version or fix this error in general?

According to the bug reports for Mongo:
mongod v2.4.9 will correctly forbid changes to collections that have a
text index which is incompatible with 2.4. Attempts to insert, update,
or remove documents in these collections will return the error message
"attempt to use unsupported textIndexVersion 2, only textIndexVersion
1 supported".
https://jira.mongodb.org/browse/SERVER-11494
I would suggest updating your Mongo version to be compatible with v2.4.9

Related

Passport JS Google oauth20 callback missing req object

I have seen some similar questions here but the answer is irrelevant to mine, as I have declared passReqToCallback.
I am trying to create an authentication system with passport. I have successfully integrated passport-local, which register/logs in user and creates a session but am having an issue in the logic of the google strategy:
passport.use(new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL,
passReqToCallback: true
},
(req, accessToken, refreshToken, profile, done) => {
/**
*
* This if statement is failing, as far as I can tell there is no req object being passed despite declaring it above
*
*/
// If user is logged in, proceed to simply link account
if (req.user) {
req.user.googleid = profile.id;
req.user.googleEmail = profile.emails[0].value;
req.user.googleDisplayName = profile.displayname;
pool.query('UPDATE users SET googleid = ?, google_email = ?, google_display_name = ? WHERE id = ?', [
req.user.googleid,
req.user.googleEmail,
req.user.googleDisplayName,
req.id
],
function(err, rows) {
// If google account is duplicate (linked to different account) will return error
if (err) {
return done(err, false, {message: "The Google account you tried to link is associated with another account."});
}
return done(null, req.user);
})
}
// Check if google account is registered
pool.query('SELECT * FROM users WHERE googleid = ?', [profile.id], function(err, rows) {
if (err) {
return done(err);
}
// If not logged in but user already registered, log in
if (rows.length) {
return done(null, rows[0]);
}
// If no existing record, register the user.
else {
let newUser = {
email: profile.emails[0].value,
// Google account specific fields
googleid: profile.id,
googleDisplayName: profile.displayName,
method: "gl", // This field ties this new user to the google account
// General fields (taken from the stuff google gives us)
firstName: profile.name.givenName,
lastName: profile.name.familyName,
googleEmail: profile.emails[0].value
}
let insertQuery = "INSERT INTO users (email, googleid, google_display_name, method, first_name, last_name, google_email) VALUES (?,?,?,?,?,?,?)";
pool.query(insertQuery, [
newUser.email,
newUser.googleid,
newUser.googleDisplayName,
newUser.method,
newUser.firstName,
newUser.lastName,
newUser.googleEmail
],
function(err, rows) {
if (err) return done(err, null);
newUser.id = rows.insertId;
return done(null, newUser);
})
}
})}));
So essentially the first if is supposed to see if the user is already authenticated and then just link the account as so. However, in practice, it will skip this even when authenticated and proceed to the rest of the logic, which works absolutely fine. It will go on to create a new account at the else statement (or return error if email is taken, I still need to implement that part).
But, interestingly, if I am logged in while using it, it doesn't log me in as the new user as it otherwise would, instead it keeps me logged in as the current session.
Where have I gone wrong? Why is the req.user not detected? I have also tried using req.isAuthenticated() with the same result.
Below is my callback route, if helpful:
// Google
router.get('/oauth/google', passport.authenticate('google', {
scope: ['email', 'profile']
}));
// Callback
router.get('/oauth/google/redirect', passport.authenticate('google', {
successRedirect: '/account',
failureFlash: 'Something went wrong. Please enable third party cookies to allow Google to sign in.',
failureRedirect: '/login'
}
));
UPDATE 1: If I try (!req.user), same result, skips to below, not sure what that means is happening

req.user is undefined in Sean.js

I'm working on a project using Sean.js and recently I tried to add a middleware to secure my api routes. I followed the "article" example using the server.policy.js and when I try to use the req.user variable it says that is undefined. I started to investigate the problem and it comes that is something to do with passport.js. I have no more than 2 months working on this and I'm not very familiar with all of this.
On the user.server.config.js is where Serelize and Deserialize the sessions:
module.exports = function(app, db) {
// Serialize sessions
passport.serializeUser(function(user, done) {
var userData = {
id: user.id,
firstName: user.firstName,
lastName: user.lastName,
displayName: user.displayName,
username: user.username,
email: user.email,
profileImageURL: user.profileImageURL,
roles: user.roles,
additionalProvidersData: user.additionalProvidersData
};
done(null, userData);
});
// Deserialize sessions
passport.deserializeUser(function(user, done) {
done(null, user);
});
// Initialize strategies
config.utils.getGlobbedPaths(path.join(__dirname, './strategies/**/*.js')).forEach(function(strategy) {
require(path.resolve(strategy))(config);
});
// Add passport's middleware
app.use(passport.initialize());
app.use(passport.session());
};
Is here the problem or should modify something else?. I believe that has something to with this because it also I have the problem that when I reload the session ends and I have to log in again.
Like the commnet above. Sean.js use Redis to store sessions, So you need to intall it first and then run it and the session will be available on req.user

Passport-ldapauth fails to execute verify callback

Please , I have setup passport ldapauth which works fine with all parameters, the problem is if the username or password is wrong, the it does not execute further to the verify callback function at all. It just stops. Due to this I cannot give feedback to the users to indicate what is actually wrong. Is there any clue what I am missing?. This is the structure
passport.use('ldapStudent', new LdapStrategy({
usernameField: 'username',
passReqToCallback:true,
server: {
url: '..........',
bindDn: '.............',
bindCredentials: '..........',
searchBase: '..............',
searchFilter: '.............',
searchAttributes: ['givenName','sn'],
tlsOptions: {
ca: [fs.readFileSync('./ssl/server.crt', 'utf8')]
}
}
},
function (req, user, done) {
//now check from the DB if user exist
if(user){
//check if user email exist;
User.findOne({'EmailAddress': user}, function (err, userdata) {
// In case of any error, return using the done method
if (err)
return done(err);
//user exist redirect to home page and send user object to session
if (userdata) {
//userActivity(PostActivity);
console.log(userdata);
return done(null, userdata);
}else {
//new user, add them to the user model
var newUser = new User();
newUser.EmailAddress = req.body.username,
newUser.JoinedDate = Date.now(),
newUser.UserType = 'Student'
newUser.save(function (err, result) {
if (err) {
console.log('Error in Saving NewUser: ' + err);
} else {
console.log(result);
var PostActivity = {
ActivityName: req.res.__('Student Joined'),
ActivityDate: Date.now(),
UserID: result._id,
UserIP: (req.header('x-forwarded-for') || req.connection.remoteAddress ) + ' Port: ' + req.connection.remotePort
};
userActivity(PostActivity);
console.log('User Registration successful');
return done(null, newUser, req.flash('SuccessMessage', req.res.__('You have been successfully Registered')));
}
})
}
});
}else{
return done(null, false, req.flash('ValidationError', req.res.__('Wrong password and/or email address')));
}}));
This is where i actually do the login
router.post('/login', passport.authenticate('ldapStudent', {
successRedirect: '/',
failureRedirect: '/userlogin',
failureFlash: true
}));
The code works well , just as I expect, the parameters for the ldap option object are intentionally omitted.
The problem is when the user credential are not correct, the verify callback does not get executed at all and so, I can not return a flash message for the user to know what is happening
passport-ldapauth does not execute the verify callback if there is nothing to verify which is the case if the credentials are incorrect and the user is not received. This is in general how the strategies tend to work, e.g. passport-local does not execute verify callback if the username or password is missing.
Strategies, passport-ldapauth included, also usually include a (configurable) message for the failure flash. General configurable login failure messages for passport-ldapauth are listed in the documentation. Each of the messages also has a default value so even when not configured the failure flash message is set (given of course that you have flash middleware in use)
Also, you are not supposed to use req.flash() in the callback of the verify function but to supply an info message.

using passport module to get facebook profile events

i am trying to get future events user attended to using passport module but im clearly missing something. i followed the Facebook API and got the permission i needed like so :
router.get('/auth/facebook', passport.authenticate('facebook', { scope: [ 'public_profile', 'user_events' ] }));
router.get('/auth/facebook/callback', passport.authenticate('facebook', {
successRedirect:'/welcome',
failureRedirect:'/'
}))
but when i am trying to print an event like this:
passport.use(new FacebookStrategy({
clientID: config.fb.appID,
clientSecret: config.fb.appSecret,
callbackURL: config.fb.callbackURL,
profileFields: ['id', 'displayName', 'photos', 'birthday', 'events', 'profileUrl', 'emails', 'likes']
}, function(accessToken, refershToken, profile, done){
//Check if the user exists in our Mongo DB database
//if not, create one and return the profile
//if exists, return profile
userModel.findOne({'profileID':profile.id}, function(err, result){
if(result){
done(null,result);
} else {
// Create a new user in our mongoLab account
var newFbUSer = new userModel({
profileID: profile.id,
fullname: profile.displayName,
profilePic:profile.photos[0].value || '',
birthday:profile.birthday,
events:profile.events[0].name,
profileUrl:profile.profileUrl,
});
console.log(newFbUSer.profilePic);
newFbUSer.save(function(err){
done(null,newFbUSer);
})
}
})
i get this error:
events:profile.events[0].name,
^
TypeError: Cannot read property '0' of undefined
i tried to replace name with value, as it is working perfectly fine with the photos, and i tried many other ways but i simply can't get this one to work...any help please?

node.js what is User in passport.js

I'm trying to make Node.js auth through steam API. I've installed passport-steam
passport.use(new SteamStrategy({
returnURL: 'http://localhost:3000/auth/steam/return',
realm: 'http://localhost:3000/',
apiKey: 'your steam API key'
},
function(identifier, profile, done) {
User.findByOpenID({ openId: identifier }, function (err, user) {
return done(err, user);
});
}
));
What is User in function?
User here is a mongoose user model.
You can read about mongoose in the docs. Mongoose is an ORM for a MongoDB database.
Passport in fact can use any store you would like and the User model there is just an example of how you can get the user and call done callback.

Resources