Skip to content

Commit

Permalink
Change crypto to be async and allow migration to use pbkdf2. Change b…
Browse files Browse the repository at this point in the history
…crypt, knox, node-expat and imagemagick to be optional dependencies.
  • Loading branch information
richtera committed Oct 14, 2012
1 parent 9a44b96 commit e5824eb
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 134 deletions.
4 changes: 3 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,9 @@ function bootApplication(cluster, next) {
// THese helpers are re-used when theme switching.
app.mwHelpers = {};

calipso.auth = {password: app.config.get('server:authentication:password')};
calipso.auth = {password: app.config.get('server:authentication:password')
, migrate2pbkdf2: app.config.get('server:authentication:migrate2pbkdf2')
};

var appId = app.config.get('server:authentication:facebookAppId');
var appSecret = app.config.get('server:authentication:facebookAppSecret');
Expand Down
3 changes: 2 additions & 1 deletion lib/conf/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"uri":"mongodb://localhost/calipso"
},
"authentication": {
"password": true
"password": true,
"migrate2pbkdf2": false
},
"server": {
"name":"Calipso",
Expand Down
12 changes: 9 additions & 3 deletions modules/core/admin/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -729,9 +729,15 @@ function coreConfig(req, res, template, block, next) {
label:'Enable password authentication and registration',
type:'checkbox',
name:'server:authentication:password',
description:'Please make sure you have made an external user (google, facebook or twitter an admin account) so you don\'t lose access to your system.',
defaultValue:true
}
description:'Please make sure you have made an external user (google, facebook or twitter an admin account) so you don\'t lose access to your system.'
},
{
label:'Enable password migration to pbkdf2 hash',
type:'checkbox',
name:'server:authentication:migrate2pbkdf2',
description:'As new people create password hashes they will be converted to pbkdf2 hashes.'
},

]
},
{ label:'Facebook Authentication (changes require a restart of calipso)',
Expand Down
25 changes: 14 additions & 11 deletions modules/core/assets/assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -1357,18 +1357,21 @@ function init(module, app, next) {
var User = calipso.db.model('User');

return User.findOne({username:clientUserName},function (err, user) {
// Check if the user hash is ok, or if there is no hash (supports transition from password to hash)
// TO BE REMOVED In later version
if(user && calipso.lib.crypto.check(clientPasswordHash,user.hash) || (user && user.hash === '')) {
if(!user.locked) {
calipso.e.post_emit('USER_LOGIN',user);
return calipso.lib.user.createUserSession(req, res, user, function(err) {
if(err) calipso.error("Error saving session: " + err);
callback(err, user);
});
}
if (err) {
return callback(new Error('Unable to authenticate user'), null);
}
if(user) {
calipso.lib.crypto.check(clientPasswordHash, user.hash, function (err, ok) {
if(!user.locked && ok) {
calipso.e.post_emit('USER_LOGIN',user);
return calipso.lib.user.createUserSession(req, res, user, function(err) {
if(err) calipso.error("Error saving session: " + err);
callback(err, user);
});
}
callback(new Error('Unable to authenticate user'), user);
});
}
callback(new Error('Unable to authenticate user'), user);
});
}
}
Expand Down
241 changes: 134 additions & 107 deletions modules/core/user/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,15 @@ function updateUserProfile(req, res, template, block, next) {
delete form.user.old_password;

User.findOne({username:username}, function(err, u) {
if(err) {
req.flash('error',req.t('Could not find user because {msg}.',{msg:err.message}));
if(res.statusCode != 302) {
res.redirect('/');
return;
}
next();
return;
}

u.fullname = form.user.fullname;
u.username = uname || form.user.username;
Expand All @@ -621,75 +630,78 @@ function updateUserProfile(req, res, template, block, next) {
if(old_password) {

// Check to see if old password is valid
if(!calipso.lib.crypto.check(old_password,u.hash)) {
if(u.hash != '') {
calipso.lib.crypto.check(old_password,u.hash, function (err, ok) {
if(u.hash != '' && !ok) {
req.flash('error',req.t('Your old password was invalid.'));
res.redirect('back');
return;
}
}

// Check to see if new passwords match
if(new_password != repeat_password) {
req.flash('error',req.t('Your new passwords do not match.'));
res.redirect('back');
return;
}

// Check to see if new passwords are blank
if(new_password === '') {
req.flash('error',req.t('Your password cannot be blank.'));
res.redirect('back');
return;
}

// Create the hash
u.hash = calipso.lib.crypto.hash(new_password,calipso.config.get('session:secret'));
u.password = ''; // Temporary for migration to hash, remove later

}

if(err) {
req.flash('error',req.t('Could not find user because {msg}.',{msg:err.message}));
if(res.statusCode != 302) {
res.redirect('/');
return;
}
next();
return;
}

calipso.e.pre_emit('USER_UPDATE',u);
u.save(function(err) {
if(err) {

req.flash('error',req.t('Could not save user because {msg}.',{msg:err.message}));
if(res.statusCode != 302) {
// Redirect to old page
res.redirect('/user/profile/' + username + '/edit');
// Check to see if new passwords match
if(new_password != repeat_password) {
req.flash('error',req.t('Your new passwords do not match.'));
res.redirect('back');
return;
}

} else {

calipso.e.post_emit('USER_UPDATE',u);

// Update session details if your account
if(req.session.user && (req.session.user.username === username)) { // Allows for name change
createUserSession(req, res, u, function(err) {
if(err) calipso.error("Error saving session: " + err);
});

// Check to see if new passwords are blank
if(new_password === '') {
req.flash('error',req.t('Your password cannot be blank.'));
res.redirect('back');
return;
}

// Redirect to new page
res.redirect('/user/profile/' + u.username);
return;

}
// If not already redirecting, then redirect
next();
});


u.password = ''; // Temporary for migration to hash, remove later
// Create the hash
calipso.lib.crypto.hash(new_password,calipso.config.get('session:secret'), function (err, hash) {
if (err) {
req.flash('error', req.t('Could not hash password because {msg}.', {msg:err.message}));
if(res.statusCode != 302) {
res.redirect('/');
return;
}
next();
return;
}
u.hash = hash;
saveUser();
});
});
} else {
saveUser();
}
function saveUser() {
calipso.e.pre_emit('USER_UPDATE',u);
u.save(function(err) {
if(err) {

req.flash('error',req.t('Could not save user because {msg}.',{msg:err.message}));
if(res.statusCode != 302) {
// Redirect to old page
res.redirect('/user/profile/' + username + '/edit');
return;
}

} else {

calipso.e.post_emit('USER_UPDATE',u);

// Update session details if your account
if(req.session.user && (req.session.user.username === username)) { // Allows for name change
createUserSession(req, res, u, function(err) {
if(err) calipso.error("Error saving session: " + err);
});
}

// Redirect to new page
res.redirect('/user/profile/' + u.username);
return;

}
// If not already redirecting, then redirect
next();
});
}
});
}
});
Expand All @@ -711,29 +723,28 @@ function loginUser(req, res, template, block, next) {
var found = false;

User.findOne({username:username},function (err, user) {
if(user) {
calipso.lib.crypto.check(form.user.password,user.hash, function (err, ok) {
if(user && !user.locked && ok) {
found = true;
calipso.e.post_emit('USER_LOGIN',user);
createUserSession(req, res, user, function(err) {
if(err) calipso.error("Error saving session: " + err);
});
}

// Check if the user hash is ok, or if there is no hash (supports transition from password to hash)
// TO BE REMOVED In later version
if(user && calipso.lib.crypto.check(form.user.password,user.hash) || (user && user.hash === '')) {
if(!user.locked) {
found = true;
calipso.e.post_emit('USER_LOGIN',user);
createUserSession(req, res, user, function(err) {
if(err) calipso.error("Error saving session: " + err);
});
}
}

if(!found) {
req.flash('error',req.t('You may have entered an incorrect username or password, please try again. If you still cant login after a number of tries your account may be locked, please contact the site administrator.'));
}

if(res.statusCode != 302) {
res.redirect(calipso.config.get('server:loginPath') || 'back');
return;
if(!found) {
req.flash('error',req.t('You may have entered an incorrect username or password, please try again. If you still cant login after a number of tries your account may be locked, please contact the site administrator.'));
}

if(res.statusCode != 302) {
res.redirect(calipso.config.get('server:loginPath') || 'back');
return;
}
next();
return;
});
}
next();
return;
});

}
Expand Down Expand Up @@ -860,36 +871,47 @@ function registerUser(req, res, template, block, next) {
}

// Create the hash
u.hash = calipso.lib.crypto.hash(new_password,calipso.config.get('session:secret'));

calipso.e.pre_emit('USER_CREATE',u);

u.save(function(err) {

if(err) {
var msg = err.message;
if (err.code === 11000) {
msg = "a user has already registered with that email";
}
req.flash('error',req.t('Could not save user because {msg}.',{msg:msg}));
calipso.lib.crypto.hash(new_password,calipso.config.get('session:secret'), function (err, hash) {
if (err) {
req.flash('error',req.t('Could not hash user password because {msg}.',{msg:msg}));
if(res.statusCode != 302 && !res.noRedirect) {
res.redirect('back');
return;
}
} else {
calipso.e.post_emit('USER_CREATE',u);
if(!res.noRedirect) {
req.flash('info',req.t('Profile created, you can now login using this account.'));
res.redirect('/user/profile/' + u.username);
return;
}
next(err);
}

// If not already redirecting, then redirect
next(err);

u.hash = hash;
saveUser();
});

function saveUser() {
calipso.e.pre_emit('USER_CREATE',u);
u.save(function(err) {

if(err) {
var msg = err.message;
if (err.code === 11000) {
msg = "a user has already registered with that email";
}
req.flash('error',req.t('Could not save user because {msg}.',{msg:msg}));
if(res.statusCode != 302 && !res.noRedirect) {
res.redirect('back');
return;
}
} else {
calipso.e.post_emit('USER_CREATE',u);
if(!res.noRedirect) {
req.flash('info',req.t('Profile created, you can now login using this account.'));
res.redirect('/user/profile/' + u.username);
return;
}
}

// If not already redirecting, then redirect
next(err);

});
}
}

});
Expand Down Expand Up @@ -1170,13 +1192,18 @@ function install(next) {
var admin = new User({
username:adminUser.username,
fullname:adminUser.fullname,
hash:calipso.lib.crypto.hash(adminUser.password,calipso.config.get('session:secret')),
email:adminUser.email,
language:adminUser.language,
about:'',
roles:['Administrator']
});
admin.save(self());
calipso.lib.crypto.hash(adminUser.password,calipso.config.get('session:secret'), function (err, hash) {
if (err) {
return self()(err);
}
admin.hash = hash;
admin.save(self());
}),

// Delete this now to ensure it isn't hanging around;
delete calipso.data.adminUser;
Expand Down
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,21 @@
"step": "0.0.x",
"optimist":"0.3.x",
"colors":"0.6.x",
"bcrypt": "0.7.x",
"semver":"1.0.x",
"zipfile":"0.3.x",
"rimraf":"2.0.x",
"nconf":"0.6.x",
"async": "0.1.x",
"hook.io": "0.8.x",
"knox": "0.0.x",
"node-expat": "1.4.x",
"imagemagick": "0.1.x",
"mailer": "~0.6.4",
"everyauth": "0.3.x"
},
"optionalDependencies": {
"bcrypt": "0.7.x",
"knox": "0.0.x",
"node-expat": "1.4.x",
"imagemagick": "0.1.x"
},
"scripts": {
"install" : "bash ./bin/install.sh",
"test" : "NODE_ENV=mocha ./node_modules/.bin/mocha --reporter spec -t 5000 -s 500"
Expand Down
Loading

0 comments on commit e5824eb

Please sign in to comment.