Merge pull request #921 from mleanos/dbseed-user-passwords

[hotfix] Fixes db seed password bug
This commit is contained in:
Liran Tal
2015-09-25 08:37:40 +03:00
4 changed files with 97 additions and 33 deletions

View File

@@ -29,56 +29,66 @@ var seedAdmin = {
roles: ['user', 'admin']
};
//If production only seed admin if it does not exist
if (process.env.NODE_ENV === 'production') {
//Add Local Admin
User.find({username: 'admin'}, function (err, users) {
User.find({username: seedAdmin.username}, function (err, users) {
if (users.length === 0) {
var password = crypto.randomBytes(64).toString('hex').slice(1, 20);
seedAdmin.password = password;
var user = new User(seedAdmin);
// Then save the user
user.save(function (err) {
if (err) {
console.log('Failed to add local admin');
} else {
console.log(chalk.bold.red('Local admin added with password set to ' + password));
}
});
// generate a random password and save
User.generateRandomPassphrase()
.then(saveUser(user))
.catch(reportError);
} else {
console.log('Admin user exists');
console.log(seedAdmin.username + ' user exists');
}
});
} else {
//Add Local User
User.find({username: 'user'}).remove(function () {
var password = crypto.randomBytes(64).toString('hex').slice(1, 20);
seedUser.password = password;
var user = new User(seedUser);
// Then save the user
user.save(function (err) {
if (err) {
console.log('Failed to add local user');
} else {
console.log(chalk.bold.red('Local user added with password set to ' + password));
}
});
});
//Add Local User
User.find({username: seedUser.username}).remove(function () {
var user = new User(seedUser);
// generate a random password and save
User.generateRandomPassphrase()
.then(saveUser(user))
.catch(reportError);
});
//Add Local Admin
User.find({username: 'admin'}).remove(function () {
var password = crypto.randomBytes(64).toString('hex').slice(1, 20);
seedAdmin.password = password;
User.find({username: seedAdmin.username}).remove(function () {
var user = new User(seedAdmin);
// generate a random password and save
User.generateRandomPassphrase()
.then(saveUser(user))
.catch(reportError);
});
}
// save the specified user with the password provided from the resolved promise
function saveUser(user) {
return function (password) {
// set the new password
user.password = password;
// Then save the user
user.save(function (err) {
if (err) {
console.log('Failed to add local admin');
console.log('Database Seeding:\t\t\tFailed to add local ' + user.username);
} else {
console.log(chalk.bold.red('Local admin added with password set to ' + password));
console.log(chalk.bold.red('Database Seeding:\t\t\tLocal ' + user.username + ' added with password set to ' + password));
}
});
});
};
}
// report the error
function reportError(err) {
console.log();
console.log('Database Seeding:\t\t\t Failed to generate random password');
console.log(err);
console.log();
}

View File

@@ -7,6 +7,7 @@ var mongoose = require('mongoose'),
Schema = mongoose.Schema,
crypto = require('crypto'),
validator = require('validator'),
generatePassword = require('generate-password'),
owasp = require('owasp-password-strength-test');
/**
@@ -166,4 +167,40 @@ UserSchema.statics.findUniqueUsername = function (username, suffix, callback) {
});
};
/**
* Generates a random passphrase that passes the owasp test.
* Returns a promise that resolves with the generated passphrase, or rejects with an error if something goes wrong.
* NOTE: Passphrases are only tested against the required owasp strength tests, and not the optional tests.
*/
UserSchema.statics.generateRandomPassphrase = function () {
return new Promise(function (resolve, reject) {
var password = '';
var repeatingCharacters = new RegExp('(.)\\1{2,}', 'g');
// iterate until the we have a valid passphrase.
// NOTE: Should rarely iterate more than once, but we need this to ensure no repeating characters are present.
while (password.length < 20 || repeatingCharacters.test(password)) {
// build the random password
password = generatePassword.generate({
length: Math.floor(Math.random() * (20)) + 20, // randomize length between 20 and 40 characters
numbers: true,
symbols: false,
uppercase: true,
excludeSimilarCharacters: true,
});
// check if we need to remove any repeating characters.
password = password.replace(repeatingCharacters, '');
}
// Send the rejection back if the passphrase fails to pass the strength test
if (owasp.test(password).errors.length) {
reject(new Error('An unexpected problem occured while generating the random passphrase'));
} else {
// resolve with the validated passphrase
resolve(password);
}
});
};
mongoose.model('User', UserSchema);

View File

@@ -228,6 +228,22 @@ describe('User Model Unit Tests:', function () {
});
});
it('should validate a randomly generated passphrase from the static schema method', function () {
var _user1 = new User(user1);
User.generateRandomPassphrase()
.then(function (password) {
_user1.password = password;
_user1.validate(function (err) {
should.not.exist(err);
});
})
.catch(function (err) {
should.not.exist(err);
});
});
it('should validate when the password is undefined', function () {
var _user1 = new User(user1);
_user1.password = undefined;

View File

@@ -35,6 +35,7 @@
"express": "^4.13.1",
"express-session": "^1.11.3",
"forever": "~0.14.2",
"generate-password": "^1.1.1",
"glob": "^5.0.13",
"grunt": "0.4.5",
"grunt-cli": "~0.1.13",