authentication using node.js and mongodb - node.js

Guys I am trying to get myself authenticated and for this I am using node.js and mongo DB.But the thing is that after registarion the user is not able to authenticate himself.Here is my snippet
app.post('/login',function(req,res){
ContactProvider.findAll(function(error, posts) {
var aut = req.body;
if (aut.user == posts.user && aut.pass == posts.pass) {
req.session.name = {name:aut.user};
res.redirect('/home');
} else {
res.send('Bad user/pass');
}
});
});
Below is my snippet for registering the user
app.post('/register',function(req, res) {
var post=req.body;
if(post.pass!=post.cpass) {
res.send("Error:Password doesnt match");
} else {
ContactProvider.save({
user: req.param('user'),
pass: req.param('pass'),
cpass: req.param('cpass'),
email: req.param('email')
}, function(error, docs) {
res.redirect('/');
});
}
});
The ContactProvider is the one below where post provider is a different file where all the mongoose things happen
var ContactProvider = require('./PostProvider').ContactProvider;
var ContactProvider= new ContactProvider();
This is the finone query in the postprovider file
ContactProvider.prototype.findone = function(name,pass, callback) {
Post.findOne({name:name},{pass:pass}, function (err, post) {
callback(null, post);
});
};

Something's seriously wrong with your code ( why you use name posts for an array of ContactProvider? ). You have to search for ContactProvider based on username and password. Something like this:
app.post('/login',function(req,res){
var aut = req.body;
ContactProvider.findOne(
{
user: aut.user,
pass: aut.pass
},
function(err, usr) {
if (error || !usr) {
res.send('Bad user/pass');
} else {
// we have a user, authenticate!
req.session.name = {name:aut.user};
res.redirect('/home');
}
}
);
});
SIDE NOTE: This is a very simple way of authenticating users, but it is not secure at all. You should read more about authentication and security in the internet. Very useful knowledge indeed.
EDIT: There's also an issue with your registration. Your data is stored in post variable, so use it on ContactProvider as well:
// some other code
ContactProvider.save({
user: post.user,
pass: post.pass,
cpass: post.cpass, // no need to store the same thing twice
email: post.email

Related

Unable to get document using document.findOne()

I tried to get a document using document.findOne() but it's value is showing undefined .
Here is my code
`app.post("/studentlogin",(req,res)=>
{
let password;
console.log("login page");
bcrypt.hash(req.body.password,saltRounds,(err,hash)=>
{
const user= Student.findOne({srno:req.body.srno});
console.log(user.srno);
if(req.body.srno==user.srno && hash==user.password)
{
session=req.username;
session.userid=req.body.srno;
res.redirect("/");
}
else{
console.log("invalid user");
res.redirect("/studentlogin");
}
});
})`
I'm implementing session authentication using express-session. Here when I log the user it's showing schema and bunch of other stuff which I don't know(The error is too long) . user.srno is also showing as undefined. How can I fix it?
I tried using call-back function which gave me required document correctly. But I want the query to return the correct document and store it in user.
Using callback function
`app.post("/studentlogin",(req,res)=>
{
let password;
console.log("login page");
bcrypt.hash(req.body.password,saltRounds,(err,hash)=>
{
Student.findOne({srno:req.body.srno},(err,result)=>
{
console.log(result);
});
//console.log(user.srno);
if(req.body.srno==user.srno && hash==user.password)
{
session=req.username;
session.userid=req.body.srno;
res.redirect("/");
}
else{
console.log("invalid user");
res.redirect("/studentlogin");
}
});
})`
You need to wait the result from your query on the database before doing the next task like comparing your password, and looks like you just try to log in, you re not going to register a new one, so it's better to use the compare method in Bcrypt like this :
app.post("/studentlogin", async (req , res) => {
const {srno, password} = req.body // destructuring your request is better for visibility
try {
const user = await Student.findOne({srno: srno});//await the result before next step
console.log(user.srno) //you can check
if(!user) {
console.log("invalid user");
// your logic to tell not student found /wrong username or password, and/or redirect
}
const isMatch = await bcrypt.compare(password, user.password) //await the result and this method for comparing the request password and the user's password found
if(!isMatch) {
//your code to tell Wrong username or password
res.redirect("/studentlogin");
} else {
// your code to access to the login.
res.redirect("/");
}
} catch (err) {
console.log(err)
}
The error you are facing is because you are not using async await in your code. use async in your function definition then use await where you are searching the database.
const someFunction = async(req,res)=>{
// your code
const user=await Student.findOne({srno:req.body.srno});
// your code
}
Your code should look like this.
app.post("/studentlogin", async(req,res)=> {
// your code
const user=await Student.findOne({srno:req.body.srno});
// your code
}
console.log(user) to verify.
Hope it helps.

How to pass extra data and check if token is valid with JWT

I just started a project where I have to use Node + few things related to it and I feel a little confused!
I use JWT for authentication, particularly I created my project like this:
api
|---teams
|----teams.controller.js
|----teams.router.js
|----teams.service.js
|---users (same as team)
auth
|---token_validation.js
other things
|---other things
I use token_validation.js for JWT to validate user while login and seems it work (verified with Postman)
const jwt = require("jsonwebtoken");
module.exports = {
checkToken: (req, res, next) => {
let token = req.get("authorization");
if (token) {
// Remove Bearer from string
token = token.slice(7);
jwt.verify(token, process.env.JWT_KEY, (err, decoded) => {
if (err) {
console.log("err: " + err);
return res.json({
success: 0,
message: "Invalid Token..."
});
} else {
req.decoded = decoded;
next();
}
});
} else {
// other code
}
}
};
I need to insert a new team in DB (MariaDB) and user can create a new team after login. My problem is that while using Session in Java for e.g. I can easly set extras like username of the logged in user and when I need to know what's the username of the logged in user is, I can take it from session
String username = (String) session.getAttribute("username");
I can't understand how to do the same with Node/JWT. What I need to do is, after login I need to save the user_id and when user crate a new team I need to send to DB the user_id with other data (if token still valid).
const {
create
} = require("./teams.service");
module.exports = {
createTeam: (req, res) => {
const body = req.body;
// here I need to check if token still valid
// if yes -> take user id and send it to DB with
// other data
create(body, (err, results) => {
if (err) { // if fails
// handle
}
return res.status(200).json({ // success
success: 1,
data: results
});
});
},
}
I thought I could add it in user.controller.js when user login:
if (result) {
results.password = undefined;
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h",
user_id: get somehow //error
});
// other code
}
but it gives me an error, tells me like I can't add user_id to sign. Can anyone please tell me the right way to store and get this kind of data and use them when needed while user still have a valid token to stay logged in?
You are adding your data to the options, not the payload.
if (result) {
results.password = undefined;
results.user_id = XXXXXXXX //get somehow
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h"
});
...
}
Best option is to set it in localStorage. When you make a req to backend send it with headers, then in backend check if token is valid and send response with data that you want.

Sockets update all the users who are subscribed to the model itself expect for the user who got updated

I have user get subscribed to chat users, the user has the ability to make himself online or offline through sockets,
One of the users have the role of the manager, where he can force users to be online or offline, through Http request User.update, and the also I added User.publishUpdate to alert the subscribers.
the problem is when the manager turn user from offline to online status, it appears that user is online to other users expect for the user himself who we updated, and the problem vanish when I enable autoWatch in sails.
here the socket code:
var query= {authType: 'google'}; //TODO this is temp, currently the staff will see only staff users, until we fix the performance issue
if (user.dealershipCompany) {
query = {
or: [{
authType: 'google',
dealershipCompany: null
}, {
authType: 'local',
dealershipCompany: user.dealershipCompany
}]
};
}
sails.log.info('Chat Users Query:\n', query);
User.find(query).exec(function (err, chatUsers) {
if (err) {
return callback(err, {
projectedUser: null,
porjectedChatUsers: null
});
} else {
// remove the logged in users to avoid self messaging
_.remove(chatUsers, {
id: userId
});
}
// Subscribe the connected socket to changes in the online state of chatUsers
User.subscribe(req.socket, chatUsers, 'update');
});
Here User update:
update: function (req, res) {
var id = req.param('id');
User.findOne(id).exec(function (err, user) {
if (err)
res.serverError(err)
else if (user) {
var firstName = req.param('firstName') || user.firstName;
var lastName = req.param('lastName') || user.lastName;
var role = req.param('role') || user.role;
var email = req.param('email') || user.email;
var online = req.param('online') || user.online;
user.firstName = firstName;
user.lastName = lastName;
user.email = email;
user.role = role;
user.online = online;
user.save(function (err, updatedUser) {
if (err)
res.serverError(err);
User.publishUpdate(updatedUser.id, {
online: updatedUser.online
}, req);
res.ok(updatedUser);
});
}
else {
res.notFound({error: 'User with id: ' + id + ' Could not be found'});
}
});
},
Well, the user doesn't get updated status because sails think that the user himself changed his own status and not the manager, the solution was to create socket listener that listen to the changes of the model and in User.update I send socket with the updatedUserId and so socket listener check if the user.id equal updatedUserId, it change their own online status.

ldapjs - write after end error

I have created an authentication service using the following code in Node.js and ldapjs.
var when = require ('when');
var AuthenticationError = require('../errors/AuthenticationError');
var SessionManagerService = require('./SessionManagerService');
var ldap = require('ldapjs');
var client = ldap.createClient({
url: 'ldaps://ad.mycompany.com:636',
tlsOptions: {'rejectUnauthorized': false}
});
module.exports = {
signIn: function (email, password) {
return this.ldapBind(email, password).then(
function () {
return SessionManagerService.createSessionHash({email: email});
}
);
},
ldapBind: function (email, password) {
var deferred = when.defer();
client.bind(email, password, function(err) {
if (err) {
deferred.reject (new AuthenticationError('Invalid username and/or password!', 'Authentication.signIn.error'));
} else {
client.unbind();
deferred.resolve(true);
}
});
return deferred.promise;
},
};
When I authenticate my user for the first time, it works perfectly but it fails starting from the second attempt.
The error message is: 'write after end'.
When I restart the node server it works again for the first attempt.
It looks like something is hanging but I don't know what. Any idea?
I solved this problem a few days ago for creating ldap-client every time in ldapBind function (in your case).

NodeJS express basicAuth - how to pass username to the route function?

I've got a working node app where I need to connect to different DBs based on what user is connecting to the app via basicAuth.
Here's a sample:
// Authenticating function
var sgAuth = express.basicAuth(function(user, pass, callback){
if(config.credentials.clients[user] === undefined) {
callback(null, false);
} else {
callback(null, config.credentials.clients[user].password == pass);
}
});
// This function needs to know what user has authenticated
function putEvents(req, res) {
//How do I know what user authenticated in this request?
var authUser = ???;
var table = getUserTable(authUser);
...
}
app.post('/put', sgAuth, putEvents);
Storing username in sgAuth to some var surely won't work, because there can be many incoming connections from different users, so you can't guarantee that its the same user, right? Can this info be retrieved from the request header somehow?
The basicAuth() middleware will set req.user and req.remoteUser once authorized.
Though, note that the 2nd argument to the callback is expected to be the user, not simply an authorized boolean. But, it can be any truthy value you desire, including the user name.
callback(null, config.credentials.clients[user].password == pass ? user : null);
After that, you should be able to retrieve it with:
var authUser = req.user;
Note that: basicAuth is deprecated
Here the code:
app.use(express.basicAuth(function(user, pass, callback){
if(config.credentials.clients[user] === undefined) {
callback('user not found!!!');
} else {
if(config.credentials.clients[user].password === pass) {
callback(null, config.credentials.clients[user]);
} else {
callback('wrong pass!!!');
}
}
});
app.post('/put', function putEvents(req, res) {
console.log(req.user.name)
res.end();
});

Resources