/* | |
Passport config for local authentication with Amazon Dynamodb | |
*/ | |
var passport = require("passport"); | |
var LocalStrategy = require('passport-local').Strategy; | |
var path = require('path'); | |
var User = require(path.join(__dirname, '/class/User')); | |
passport.serializeUser(function(user, done) { | |
done(null, user.login); | |
}); | |
passport.deserializeUser(function(login, done) { | |
//return the user object to callback done | |
//Conect to Dynamodb | |
var ddb = require('dynamodb').ddb({ | |
accessKeyId: process.env.DYNAMODB_ACCESSKEYID, | |
secretAccessKey: process.env.DYNAMODB_SECRETACCESSKEY, | |
endpoint: process.env.DYNAMODB_ENDPOINT | |
}); | |
//return user by login | |
ddb.getItem('user', login, null, {}, function(err, item, cap) { | |
done(err, item); | |
}); | |
}); | |
passport.use(new LocalStrategy( | |
function(user, pass, done) { | |
//Conect to Dynamodb | |
var ddb = require('dynamodb').ddb({ | |
accessKeyId: process.env.DYNAMODB_ACCESSKEYID, | |
secretAccessKey: process.env.DYNAMODB_SECRETACCESSKEY, | |
endpoint: process.env.DYNAMODB_ENDPOINT | |
}); | |
//return user by login | |
ddb.getItem('user', user, null, {}, function(err, item, cap) { | |
if (err) { | |
//return the response from callback when an error happen | |
return done(err); | |
} else { | |
if (item && User.hash(pass, item.salt) === item.hash) { | |
//return the response from callback when the login is ok | |
return done(null, item); | |
} else { | |
//return the response from callback when the login is invalid | |
return done(null, false, { | |
message: 'Login Invalid' | |
}) | |
} | |
} | |
}); | |
})); | |
module.exports = passport; |
you have some vulnerabilities in your code though.
I would not recommend using this snippet.
I recommend Building a User Object like the one used in jareds example:
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); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
And be careful about salting. If you save a salt per user, and someone is able to steal database objects, he also has the matching salt.
A salt should be saved somewhere else.
Security-wise it does not make a difference if you have the same salt for every user or use an individual salt. The aim of a salt is to increase the entropy of brute attacks on the raw hashes.
So basically, if you save the salt next to the hash, it prevents the hacker from attacking all the passwords at the same time, which is more time consuming but not really safer as long as you use a crappy hash function (unless you use bcrypt or PBKDF2 etc..).
one good explanation of this problem is here
I just wanted to say this to warn unexperienced developers.
In contrast to @julianbei - storing the salt as part of the protected credential is fine according to OWASP:
Scheme security does not depend on hiding, splitting, or otherwise obscuring the salt
https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
Basically it shouldn't matter if the salt is exposed - it's just meant to make it difficult for someone to quickly recover all passwords from a database. What is important is that every credential should have a unique salt - do not use one salt for all records. If you can build a rainbow table based on the same salt used for all credentials you can more easily recover all credentials en masse. If you're using bcrypt it will generate a unique salt per credential by default (the salt is normally part of the generated output), although you should ideally now use argon2.
On using the above code. I'm facing the " TypeError: callback.call is not a function issue"
just as a small improvement suggestion with ES6 and AirBnB styleguide