mudra
Version:
Mudra is a simple authentication and authorisation library for NodeJS that uses MongoDB for storing credentials. (Full Info: https://github.com/baliganikhil/mudra.js)
403 lines (309 loc) • 8.88 kB
JavaScript
var mongoose = require('mongoose');
var bcrypt = require('bcrypt');
var Q = require('q');
var fs = require('fs');
var connection = 'mongodb://localhost/mudra';
try {
var config = fs.readFileSync('./config.local');
config = JSON.parse(config);
var host = config.mongo.host;
var db = config.mongo.db;
connection = ['mongodb:/', host, db].join('/');
} catch(e) {
}
mongoose.connect(connection);
/************************************/
var User = mongoose.Schema({
username: {type: String, required: true, index: {unique: true}},
name: String,
hash: {type: String, required: true}
});
var _users = {
username: {type: String, required: true, index: {unique: true}},
name: String
};
var Role = mongoose.Schema({
role: {type: String, required: true, index: {unique: true}},
users: [_users]
});
var Context = mongoose.Schema({
context: {type: String, required: true},
users: [_users]
});
var Permission = mongoose.Schema({
permission: {type: String, required: true, index: {unique: true}},
roles: [{
role: {type: String, required: true, index: {unique: true}},
}],
context: [Context]
});
User = mongoose.model('User', User);
Role = mongoose.model('Role', Role);
Permission = mongoose.model('Permission', Permission);
/************************************/
exports.register = function(payload, callback) {
var deferred = Q.defer();
if (noe(callback)) {
callback = function() {};
}
var username = payload.username;
var password = payload.password;
if (noe(username) || noe(password)) {
var payload = {status: 'error', message: 'Username and password are mandatory fields'};
deferred.reject(payload);
callback(payload);
return deferred.promise;
}
create_auth_token(username, password).then(save_user, function(err) {
return_error(err, deferred, callback);
});
function save_user(hash) {
delete payload.password;
payload.hash = hash;
(new User(payload)).save(function(err, doc) {
if (err) {
deferred.reject(err);
callback({status: 'error', data: doc});
return false;
}
deferred.resolve(doc);
});
}
return deferred.promise;
};
exports.login = function(payload, callback) {
var deferred = Q.defer();
if (noe(callback)) {
callback = function() {};
}
var username = payload.username;
var password = payload.password;
User.findOne({username: username}, function(err, user) {
if (err) {
return_error(err, deferred, callback);
return;
}
if (noe(user)) {
return_error('No such user found', deferred, callback);
return;
}
bcrypt.compare(password, user.hash, function(err, result) {
if (err) {
return_error(err, deferred, callback);
return;
}
var payload = {status: 'success', data: user};
if (result) {
callback(payload);
deferred.resolve(payload);
} else {
return_error('Password did not match', deferred, callback);
}
});
});
return deferred.promise;
};
exports.authenticate = function(payload, callback) {
var deferred = Q.defer();
if (noe(callback)) {
callback = function() {};
}
var username = payload.username;
var hash = payload.hash;
User.findOne({username: username}, function(err, user) {
if (err) {
return_error(err, deferred, callback);
return;
}
if (noe(user)) {
return_error('No such user found', deferred, callback);
return;
}
if (user.hash === hash) {
var payload = {status: 'success', data: 'authenticated'};
deferred.resolve(payload);
callback(payload);
return;
} else {
var payload = 'User not authenticated';
return_error(payload, deferred, callback);
return;
}
});
return deferred.promise;
};
exports.reset_password = function(payload, callback) {
var deferred = Q.defer();
var username = payload.username;
var password = payload.password;
exports.authenticate(payload).
then(function(payload) {
create_auth_token(username, password).then(function(hash) {
User.update({username: username}, {hash: hash}, function(err) {
if (err) {
return_error(err, deferred, callback);
return;
}
var payload = {status: 'success', data: 'Password reset'};
deferred.resolve(payload);
callback(payload);
});
}, function(err) {
return_error(err, deferred, callback);
});
}, function(payload) {
return_error(payload, deferred, callback);
});
return deferred.promise;
};
exports.create_role = function(params, callback) {
var deferred = Q.defer();
if (noe(callback)) {
callback = function() {};
}
(new Role(params)).save(function(err, doc) {
if (err) {
return_error(err, deferred, callback);
return false;
}
var payload = {status: 'success', data: doc};
deferred.resolve(payload);
callback(payload);
});
return deferred.promise;
};
exports.create_permission = function(params, callback) {
var deferred = Q.defer();
if (noe(callback)) {
callback = function() {};
}
(new Permission(params)).save(function(err, doc) {
if (err) {
return_error(err, deferred, callback);
return false;
}
var payload = {status: 'success', data: doc};
deferred.resolve(payload);
callback(payload);
});
return deferred.promise;
};
exports.update_role = function(params, callback) {
var deferred = Q.defer();
if (noe(callback)) {
callback = function() {};
}
var role = params.role;
Role.findOne({role: role}, function(err, role) {
if (err) {
return_error(err, deferred, callback);
return false;
}
if (noe(role)) {
return_error('No such role found', deferred, callback);
return;
}
role = JSON.parse(JSON.stringify(role));
role.users = params.users;
delete role._id;
Role.findOneAndUpdate({role: role.role}, role, function(err) {
if (err) {
return_error(err, deferred, callback);
return false;
}
var payload = {status: 'success', data: role};
deferred.resolve(payload);
callback(payload);
});
});
return deferred.promise;
};
exports.update_permission = function(params, callback) {
var deferred = Q.defer();
if (noe(callback)) {
callback = function() {};
}
var permission = params.permission;
Permission.findOne({permission: permission}, function(err, permission) {
if (err) {
return_error(err, deferred, callback);
return false;
}
if (noe(permission)) {
return_error('No such permission found', deferred, callback);
return;
}
permission = JSON.parse(JSON.stringify(permission));
permission.roles = params.roles;
delete permission._id;
Permission.findOneAndUpdate({permission: permission.permission}, permission, function(err) {
if (err) {
return_error(err, deferred, callback);
return false;
}
var payload = {status: 'success', data: permission};
deferred.resolve(payload);
callback(payload);
});
});
return deferred.promise;
};
exports.check_permission = function(params, callback) {
var deferred = Q.defer();
if (noe(callback)) {
callback = function() {};
}
exports.authenticate(params).then(
function() {
var permission = params.permission;
var context = params.context;
var username = params.username;
console.log(context);
Role.find({"users.username": username}, {role: 1, _id: 0}, function(err, docs) {
if (err) {
return_error(err, deferred, callback);
return false;
}
var roles = [];
docs.forEach(function(role) {
roles.push(role.role);
});
Permission.findOne({permission: permission, '$or': [{"roles.role": {'$in': roles}}, {"context.roles": {"$in": roles}, "context.context": context}]}, function(err, doc) {
if (err) {
return_error(err, deferred, callback);
return false;
}
if (doc === null) {
return_error('Unauthorised', deferred, callback);
return;
}
var payload = {status: 'success', data: 'Authorised'};
deferred.resolve(payload);
callback(payload);
});
});
},
function(err) {
return_error(err, deferred, callback);
});
return deferred.promise;
};
function create_auth_token(username, password) {
var deferred = Q.defer();
bcrypt.hash(password, 8, function (err, hash) {
if (err) {
return_error(err, deferred, callback);
return false;
}
deferred.resolve(hash);
});
return deferred.promise;
}
function return_error(err, deferred, callback) {
var payload = {status: 'error', data: err};
deferred.reject(payload);
callback(payload);
}
function noe(i) {
return [undefined, null, ''].indexOf(i) > -1;
}