webgme-engine
Version:
WebGME server and Client API without a GUI
215 lines (183 loc) • 7.37 kB
JavaScript
/*globals*/
/*eslint-env node*/
/**
* @author pmeijer / https://github.com/pmeijer
*/
;
var AuthorizerBase = require('./authorizerbase'),
GME_AUTH_CONSTANTS = require('./constants'),
Q = require('q');
function DefaultAuthorizer(mainLogger, gmeConfig) {
var self = this;
self.collection = null;
AuthorizerBase.call(self, mainLogger, gmeConfig);
function _getProjection(/*args*/) {
var ret = {},
i;
for (i = 0; i < arguments.length; i += 1) {
ret[arguments[i]] = 1;
}
return ret;
}
function getProjectAuthorizationByUserOrOrgId(userId, projectId, callback) {
var ops = ['read', 'write', 'delete'];
return self.collection.findOne({
_id: userId,
disabled: { $ne: true }
}, _getProjection('siteAdmin', 'orgs', 'projects.' + projectId))
.then(function (userData) {
if (!userData) {
return Q.reject(new Error('no such user [' + userId + ']'));
}
if (userData.siteAdmin) {
return [{}, [true, true, true]];
}
userData.orgs = userData.orgs || [];
return [userData.projects[projectId] || {},
Q.all(ops.map(function (op) {
// Check if the user is in any org that has project access.
var query;
if ((userData.projects[projectId] || {})[op]) {
return 1; // user has the right
}
if (userData.orgs.length === 0) {
return 0; // no orgs to check
}
query = { _id: { $in: userData.orgs }, disabled: { $ne: true } };
query['projects.' + projectId + '.' + op] = true;
return self.collection.findOne(query, { _id: 1 });
}))];
}).spread(function (user, rwd) {
// merge them together
var ret = {};
ops.forEach(function (op, i) {
ret[op] = (user[op] || rwd[i]) ? true : false;
});
return ret;
})
.nodeify(callback);
}
function removeProjectRightsForAll(projectId, callback) {
var update = { $unset: {} };
update.$unset['projects.' + projectId] = '';
return self.collection.updateMany({}, update)
.nodeify(callback);
}
/**
*
* @param userId {string}
* @param callback
* @returns {*}
*/
function getUser(userId, callback) {
return self.collection.findOne({
_id: userId,
type: { $ne: GME_AUTH_CONSTANTS.ORGANIZATION },
disabled: { $ne: true }
})
.then(function (userData) {
if (!userData) {
return Q.reject(new Error('no such user [' + userId + ']'));
}
delete userData.passwordHash;
userData.data = userData.data || {};
userData.settings = userData.settings || {};
return userData;
})
.nodeify(callback);
}
function getAdminsInOrganization(orgId, callback) {
return self.collection.findOne({ _id: orgId, type: GME_AUTH_CONSTANTS.ORGANIZATION, disabled: { $ne: true } },
{ admins: 1 })
.then(function (org) {
if (!org) {
return Q.reject(new Error('no such organization [' + orgId + ']'));
}
return org.admins;
})
.nodeify(callback);
}
/**
*
* @param userOrOrgId {string}
* @param projectId {string}
* @param type {string} 'set', 'delete'
* @param rights {object} {read: true, write: true, delete: true}
* @param callback
* @returns {*}
*/
function authorizeByUserOrOrgId(userOrOrgId, projectId, type, rights, callback) {
var update;
if (type === 'set') {
update = { $set: {} };
update.$set['projects.' + projectId] = rights;
} else if (type === 'delete') {
update = { $unset: {} };
update.$unset['projects.' + projectId] = '';
} else {
return Q.reject(new Error('unknown type ' + type))
.nodeify(callback);
}
return self.collection.updateOne({ _id: userOrOrgId, disabled: { $ne: true } }, update)
.then(function (result) {
if (result.matchedCount !== 1) {
return Q.reject(new Error('no such user or org [' + userOrOrgId + ']'));
}
})
.nodeify(callback);
}
this.getAccessRights = function (userId, entityId, params, callback) {
if (params.entityType === AuthorizerBase.ENTITY_TYPES.PROJECT) {
return getProjectAuthorizationByUserOrOrgId(userId, entityId)
.nodeify(callback);
} else if (params.entityType === AuthorizerBase.ENTITY_TYPES.USER) {
return getUser(userId)
.then(function (user) {
const readOnly = { read: true, write: false, delete: false };
const readWrite = { read: true, write: true, delete: false };
if (user.siteAdmin) {
return { read: true, write: true, delete: true };
}
if (!user.canCreate) {
return readOnly;
}
if (userId === entityId) {
return readWrite;
}
return getAdminsInOrganization(entityId)
.then(function (admins) {
if (admins.indexOf(userId) > -1) {
return readWrite;
}
return readOnly;
});
})
.nodeify(callback);
}
};
this.setAccessRights = function (userId, entityId, rights, params, callback) {
var revoke = rights.read === false && rights.write === false && rights.delete === false,
promise;
if (params.entityType === AuthorizerBase.ENTITY_TYPES.PROJECT) {
if (userId === true) {
promise = removeProjectRightsForAll(entityId);
} else if (revoke) {
promise = authorizeByUserOrOrgId(userId, entityId, 'delete');
} else {
promise = authorizeByUserOrOrgId(userId, entityId, 'set', rights);
}
} else {
throw new Error('Only ENTITY_TYPES.PROJECT allowed when setting access rights!');
}
return promise.nodeify(callback);
};
this.start = function (params, callback) {
var deferred = Q.defer();
self.collection = params.collection;
deferred.resolve();
return deferred.promise.nodeify(callback);
};
}
DefaultAuthorizer.prototype = Object.create(AuthorizerBase.prototype);
DefaultAuthorizer.prototype.constructor = DefaultAuthorizer;
module.exports = DefaultAuthorizer;