With the following code I'm not able to authenticate with a MongoDB database, which already has a Users schema and users associated with it and I was wondering how I would make sure that auth returned isAuth?:
exports.auth = function(username, password, session) {
User.findOne({username: username}, function(err, data) {
if (err) {
console.log(err);
}
var isAuth = username === data['username'] & password === data['password'];
if (isAuth) {
session.isAuthenticated = isAuth;
session.user = {username: username};
}
return isAuth;
});
};
First of all, as others have already pointed out in the comments, you shouldn't implement your own authentication logic if you don't know what you're doing. You can use Passport for that.
Now, to the code you provided. There are several problems here.
The first thing that comes to mind is that you use:
var isAuth = username === data['username'] & password === data['password'];
instead of:
var isAuth = username === data['username'] && password === data['password'];
But this is just a typo. Now, to more fundamental stuff.
You cannot return the isAuth variable because who are you going to return it to? If you think that it will get returned to the caller of exports.auth then you're wrong - the exports.auth() will return long before the return isAuth; is ever run.
Also, if yu check for error with if (err) then put the code that should be run in the case of success in the else block o otherwise it will also be run on error with undefined variables that may crash your program.
You need to either add an additional argument to your function which is a callback:
exports.auth = function(username, password, session, callback) {
User.findOne({username: username}, function(err, data) {
if (err) {
console.log(err);
callback(err);
} else {
var isAuth = username === data.username && password === data.password;
if (isAuth) {
session.isAuthenticated = isAuth;
session.user = {username: username};
}
callback(null, isAuth);
}
});
};
or to return a promise from your exports.auth function (but directly from your exports.auth function, not some other callback inside).
Using the above version you can call it with:
auth(username, password, session, function (isAuth) {
// you have your isAuth here
});
The other option would be to use promises. You can see some other answers where I explain the difference between callbacks and promises and how to use them together in more detail, which may be helpful to you in this case:
A detailed explanation on how to use callbacks and promises
Explanation on how to use promises in complex request handlers
An explanation of what a promise really is, on the example of AJAX requests
But first you need to get comfortable with callbacks.
Also, never store the passwords in cleartext in the database. Seriously, use some other solution that works like Passport. I wrote the answer to explain the process of using callbacks, not to endorse the idea of using authentication in that particular way. You have been warned.
Related
I'm using postgresql(Elephant SQL) and I hadnt had issues creating and finding users inside this database. And this is my method. It's pretty straight forward and most of it shouldn't even matter to the question. What I'm lacking is the ability to change a users password, or anything really. It finds the correct user and pretty much anything up to the point where it needs to change an entry works as expected.
updatePassword: async function(req,res){
if(req.body.password){
console.log("PUT BODY" + req.body.password);
var newPass = req.body.password;
var userId = req.session.userId;
var foundUser = await User.findOne({id:userId},function(err,user){
if(err){
return res.status(500).json({err:'database error'});
}
if(user){
var hashedPass = bcrypt.hashSync(newPass, bcrypt.genSaltSync(8), null);
console.log("Found user");
console.log(userId);
console.log(hashedPass);
var updateUser = User.update(user).set({password:hashedPass}).fetch();
console.log(updateUser);
if(updateUser){
return res.status(200).json({status:'success'});
}
else{
return res.status(500).json({err:'database error'});
}
}
if(!user){
return res.status(500).json({err:'database error'});
}
});
}
else{
return res.status(401).json({err:'empty body'});
}
},
I've been debugging this for quite some time and I can't figure it out at all. The user found is correct and I can get his current attributes, but I can in no way change their passwords.
Can anyone provide some insight? Maybe adding some stuff: this is a PUT request, only containing:
password:iaj34x
I can also parse the request alright. All I'm missing is the update command executing properly. The value of
updateUser
is
[Deferred]
And I have no idea how to get any more info on this.
Using this as an example(from the docs):
await User.update({name:'Pen'})
.set({name:'Finn'});
I'm doing the syntax correctly.
Was missing an await next to the function. "Works" now, even though I have issues with re-logins, it changes the password in the database.
var updateUser = await User.update(user).set({password:hashedPass}).fetch();
I'm still having trouble with conditionals and database callbacks, I wrote a routing function that querys for a violation object and this is from a form filled out in the client side. I am trying to change the user that owns this violation as an option, I query for that user and return it fine however at the if statement, x != y will always return true because of the nature of how I wrote this. I want it to finish querying, and then hit the conditional. I feel kind of stuck on how to go about this.
if(viol.user != user[0]._id)
That way when I edit the user who owns that violation or object, the user doesn't add the same object to itself over and over again.
app.post('/singleViolation/:violation', isAdmin, function(req, res) {
var violation = req.params.violation;
Violation.findById(violation, function(err, viol){
if (err) throw err;
if (req.body.cause === '') {
req.body.cause = viol.cause;
}
if (req.body.date === '') {
req.body.date = viol.date;
}
if (req.body.location === '') {
req.body.location = viol.location;
}
if(req.body.email === '') {
req.body.email == viol.user;
}
if( req.body.email != '') {
User.find({"local.email" : req.body.email}, function (err, user) {
if (err) {
req.body.email = viol.user;
}
if(viol.user != user[0]._id) {
typeof viol.user;
typeof user[0].id;
console.log(viol.user);
console.log(user[0]._id);
console.log(viol.user === user[0].id);
viol.user = user[0];
viol.save();
user[0].local.violations.push(viol);
Vehicles.findById(viol.vehicle, function(err, veh) {
user[0].local.vehicles.push(veh);
veh.owner = user[0];
veh.save();
user[0].save();
});
}
});
}
viol.cause = req.body.cause;
viol.date = req.body.date;
viol.location = req.body.location;
viol.save();
});
res.json(req.body);
});
app.get('/editViolations/:violations', isAdmin, function(req, res) {
res.render('editViolations.ejs');
});
You need to use Events in order to achieve what you want. Below is just a high-level solution.
Trigger an Event when quering is finished.
Associate the above event to you condition statement.
Trigger another event when you meet your required condition.
Associate this event with your return statement.
Read this good tutplus blog to wrap your head around node event module.
I believe you should first go through the concepts of callback functions and how to avoid callback hell
Below links would help you kick start with callbacks
understanding callback functions
callback hell
The question:
In a nutshell - how can I invoke the passport serializeUser function directly ? I am happy with the registered implementaiton I have provided, i just need to be able to invoke it without the indirection of calling authenticate in order to do so.
passport.serializeUser(function (user, done) {
if (user) {
done(null, user);
}
});
As an already authenticated user, inside a Controller, I want to be able to do something like:
var user = req.user; // get the already authenticated user out of the session
user.roles = ['agency']
passport.serializeUser(user); // persist my changes in session storage
deserializeUser will know how to handle the changes.
Background:
Have a working MEAN Stack application using Passport for authentication with a local strategy. Everything works great - the session management is externalized to Redis. However, there is a requirement in the application to be able to "LOGON AS" another type of user to the System. An administrator (user with admin role) can for example log on as one of the users. In effect, I want this to be an illusion - all i will do is alter a few settings about the admin (role information etc and store that in session - the altered data is stored in a stack (js array - memento pattern concept) - and when the admin does a user logoff i pop the original info about the admin back into his session data.
So really what I want is the ability to tweak a few User details about the Admin user already logged in and update their session information with these changes (serialize them) without re-authenticating (apart from anything else I don't have the unencrypted password to call authenticate so that is not an option). The admin is already authenticated. - on deserializeUser the logic will check for enriched data, and if present do the right thing when deserializing the data to keep the impression that the admin is the assumed user identity.
Update:
Ok, so it looks like the behaviour is very different to what I originally expected. As follows:
1). passport.serializeUser appears to only ever be called on authenticate (login). passport.deserializeUser however gets called on every request, and often several times - therefore if putting a DB query in there, expect several queries per request to be possible.
2). req.user is the object that gets updated by passport.deserializeUser. This is DISTINCT from req._passport.session.user !! They are not the same...
3). req._passport.session.user is what updates the session store directly. Hence if you change what req._passport.session.user points at, or alter its attributes, they will internally update the session storage - I can see this behaviour by looking at the session state in Redis DB.
To solve my problem above, i don't actually need to directly call passport.serializeUser. I only need to update the req._passport.session.user with the attribute information i want persisted to session storage. But here is a key point - I believe the attributes that can be updated must match attributes that were already present when passport.serializeUser was originally used to serialize out the initial state. That last point is to be confirmed.
So I can update req._passport.session.user, and it gets persisted to session storage so long as it abides to attributes already stored in the session. Then I can override the behaviour of passport.deserializeUser to use what is passed in as an argument. Again, here is a confusing point - what is passed in as a user argument to passport.deserializeUser is the req._passport.session.user object, and what eventually gets returned by passport.deserializeUser is the req.user object accessible later on.
https://github.com/jaredhanson/passport/blob/master/lib/http/request.js
function here....
...
var self = this;
this._passport.instance.serializeUser(user, this, function(err, obj) {
if (err) { self[property] = null; return done(err); }
self._passport.session.user = obj;
done();
});
Ok, so Passport is really flexible here and accommodates exactly what I needed. Just need to first get up to speed with how it has been implemented internally. Here, I shall call the solution "Parasitic Session Polymorphism" because of the way it uses the existing session, but injects just enough new information to appear to be a different user type etc at runtime. So the solution is basically (with custom code that would need to be swapped out if anyone wishes to use the basic idea):
passport.serializeUser(function (user, done) {
if (user) {
var identityStack = user.identityStack || [];
var parentId = user.parentId || '';
var userStorage = {
_id: user._id,
identityStack: identityStack,
entityId: user.entityId,
entityType: user.entityType,
roles: user.roles,
parentId: parentId
};
done(null, userStorage);
}
});
passport.deserializeUser(function (userStorage, done) {
var id = userStorage._id;
User.findOne({_id: id}).exec(function (err, user) {
if (user) {
if(userStorage.identityStack && userStorage.identityStack.length > 0) {
user.identityStack = userStorage.identityStack;
user.entityId = userStorage.entityId;
user.entityType = userStorage.entityType;
user.roles = userStorage.roles;
user.parentId = userStorage.parentId
}
return done(null, user);
} else {
return done(null, false);
}
});
});
Then in order to actually call the passport.serializeUser from within your own code, you can achieve the required result by currying the http req object. For my implementation I push and pop the added information off a javascript array associated with .prototype as an extension to the Mongoose User Model:
PUSH KEY CODE:
var memento = {
entityId : agency.id,
entityType: 'user',
roles: ['admin', 'user']
};
var user = req.user;
user.pushIdentity(memento);
var doneWrapper = function (req) {
var done = function (err, user) {
if(err) {
console.log('Error occurred serializing user');
return;
}
req._passport.session.user = user;
console.log('user serialized successfully');
return;
};
return done;
};
req._passport.instance.serializeUser(user, doneWrapper(req));
return res.send({success: true, user: req.user});
and POP KEY CODE:
var user = req.user;
user.popIdentity();
var doneWrapper = function (req) {
var done = function (err, user) {
if(err) {
console.log('Error occurred serializing user');
return;
}
req._passport.session.user = user;
console.log('user serialized successfully');
return;
};
return done;
};
req._passport.instance.serializeUser(user, doneWrapper(req));
return res.send({success: true, user: user});
Clearly the code is not yet production ready, move out the console.log statements to a logging strategy and so on but that is the basic concept. The signature to the serializeUser method is defined in the Passport github code base under lib/authenticator.js.
KEY PART:
Authenticator.prototype.serializeUser = function(fn, req, done) {
if (typeof fn === 'function') {
return this._serializers.push(fn);
}
// private implementation that traverses the chain of serializers, attempting
// to serialize a user
var user = fn;
// For backwards compatibility
if (typeof req === 'function') {
done = req;
= undefined;
}
Thanks to Biba for his contributions, really appreciated and assisted in getting to a solution.
I have a function running in a node app that I can't get to work due to my lack of understanding on how to write asynchronous code properly. Below is a function that takes in a profile with emails. I would like to loop through each email and check to see whether that user exists in my database. If they do, I would like to return the callback given and completely exist the function without doing anything else. If the user is not found, I would then like to create a new user based on the information given in the profile, and then return the same callback with the newly created user. As of now, the function works as intended, except that it creates a new user even when a user is already found in my database. (the 'User' variable is defined above and has the 'create' function. Also, I would like to avoid using the 'async' node module if at all possible)
function processProfile(profile, callback) {
var existingUser;
if (profile.emails) {
profile.emails.forEach(function(email) {
console.log("Searching for user with this email:" + email.value);
existingUser = findUserByEmail(email.value);
if (existingUser) {
console.log("Found the existing user");
return callback(null, existingUser);
}
});
if(!existingUser){
console.log("Creating new user");
var newUser = {
id: profile.id,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
email: profile.emails[0].value
};
user.create(newUser, profile.provider, function(err, user) {
if (err) throw err;
return callback(null, user);
});
}
}
}
Is there something wrong with this?
function processProfile(profile, callback) {
var existingUser;
var index = 0;
function processNextEmail() {
if(index >= profile.emails.size()) return; //When we've popped nothing exit
var email = profile.emails[index++];
console.log("Searching for user with this email:" + email.value);
existingUser = findUserByEmail(email.value);
if (existingUser) {
console.log("Found the existing user");
callback(null, existingUser);
processEmail();//recursive call to prcess the next email
} else {
console.log("Creating new user");
var newUser = {
id: profile.id,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
email: profile.emails[0].value
};
user.create(newUser, provider, function(err, user) {
if (err) throw err;
callback(null, user);
processNextEmail();//recursive call to process the next email after creating the user and adding it to the database.
});
}
}
processNextEmail();
}
If you need the recursive logic to not remove the emails, you can do a simple modification involving an indice within the scope of the processProfile() closure.
Also note, the return callback() lines, don't really do anything. Returning from functions that are happening asynchronously is a waste of time. Just call the callback, and then you can call an empty return to skip the rest of the function if you wish, but it is unecessary, unless the return effects the flow of logic.
EDIT: It turns out this is example is too simple to be much more interesting. The code below I used as an example for some people at work who were having trouble grasping async code. The one time I think that it is okay to use sync code in node is for gathering configuration data. Let's pretend that we have configuration stored in a file, that in turn gets the filename from that file, and gathers another layer of configuration data from another file. We can do this two ways, using readFileSyn, or using readFile. The asynchronous version is tricky, because we need to wait for the first step to complete, because we have to grab the filename from the first file, in order to know where the second file is stored. Below is the code for both the sync solution and async solution.
//The synchronous way
function useConfigurationData(configData) {
dosomethinginterestingwith(configData);
}
function getConfigurationData(fileName) {
var fileName2 = fs.readFileSync(fileName);
var configurationData = fs.readFileSync(fileName2);
return configurationData;
}
var fileData = getConfigurationData('someFile');
useConfigurationData(fileData);
//The equivalent async way
function getConfigurationData(fileName, useConfigDataCallBack) {
fs.readFile(fileName, getConfigDataStepTwo);
function getConfigDataStepTwo(err, fileName2) {
fs.readFile(fileName2, getConfigDataStepThree);
}
function getConfigDataStepThree(err, fileData) {
useConfigDataCallBack(fileData);
}
}
getConfigurationData('someFile', useConfigurationData);
Notice that the callback we supply to getConfigurationData is the last step. We could also just rely on the globally defined getConfigurationData function, but passing it in as a callback is better style.
What I like about this syntax, is the code withing the second getConfigurationData function reads in order, very synchronously. But if you follow the flow of logic, it is all being run async. It's easy to read and follows nodes async I/O model. IN the case of configuration data, I think the synchronous option is acceptable, but this is still a good demo of how to get synchronous behavior and syntax(ish) from asynchronous callbacks.
I am little bit confused with my code it's not worked synchronusly as it's should be. I use everyauth to do authentication.
registerUser(function(newUserAttrs) {
var login = newUserAttrs[this.loginKey()];
user.CreateNewUser(newUserAttrs.login, newUserAttrs.password, newUserAttrs.email, function(res, err) {
if(!err) {
return usersByLogin[login] = newUserAttrs;
}
else {
throw err;
}
});
})
in another file I have write this code
exports.CreateNewUser = function(login, pass, mail, callback) {
var sql = "insert into `user`(login,mail,pass) values(?,?,?)";
client.query(sql, [login, mail, pass], function(err, results, fields) {
if(!err) {
callback(results);
console.log('test')
}
else {
callback(results, err);
}
});
};
This code are working fine. I have tested him. the only problem is they are working synchronosly (as normal). Can someone explain me what thing I have done in wrong way that make it async. I want to get it done in sync way.
The current code give me error (it's make a entry in database and produce error on browser)
Error: Step registerUser of `password` is promising: userOrErrors ; however, the step returns nothing. Fix the step by returning the expected values OR by returning a Promise that promises said values.
at Object.exec (E:\proj\Node\node_modules\everyauth\lib\step.js:68:11)
at E:\proj\Node\node_modules\everyauth\lib\stepSequence.js:26:38
at [object Object].callback (E:\proj\Node\node_modules\everyauth\lib\promise.js:13:12)
at RouteTriggeredSequence._bind (E:\proj\Node\node_modules\everyauth\lib\stepSequence.js:25:20)
at RouteTriggeredSequence.start (E:\proj\Node\node_modules\everyauth\lib\stepSequence.js:52:33)
at RouteTriggeredSequence.routeHandler (E:\proj\Node\node_modules\everyauth\lib\routeTriggeredSequence.js:13:13)
at Object.<anonymous> (native)
at nextMiddleware (E:\proj\Node\node_modules\connect\lib\middleware\router.js:175:25)
at param (E:\proj\Node\node_modules\connect\lib\middleware\router.js:183:16)
at pass (E:\proj\Node\node_modules\connect\lib\middleware\router.js:191:10)
Thanks
The two pieces of code you present are asynchronous and not synchronous!
With everyauth, to be able to handle asynchronous user creation you should use a Promise. So your code will be something like :
registerUser(function(newUserAttrs) {
var promise = this.Promise();
var login = newUserAttrs[this.loginKey()];
user.CreateNewUser(newUserAttrs.login, newUserAttrs.password, newUserAttrs.email, function(res, err) {
if(!err) {
return promise.fulfill(newUserAttrs);
}
else {
promise.fulfill(user);
}
});
})
Without promise you couldn't be sure that your new user has been added in your database. But if it doesn't matter you could have something like that:
registerUser(function(newUserAttrs) {
var login = newUserAttrs[this.loginKey()];
user.CreateNewUser(newUserAttrs.login, newUserAttrs.password, newUserAttrs.email, function(res, err) {
if (err) console.log(err);
});
return newUserAttrs;
})
Because you are doing a database query, this code has to be asynchronous. The anonymous function you pass to client.query will not be called until the database query is complete, so your callback gets called asynchronously.
You will need to treat this all as asynchronous, so for instance you'll have to trigger some other callback instead of returning the user object/throwing.