'use strict';
/**
* @module core
*/
var async = require('async');
var openVeoApi = require('@openveo/api');
var UserProvider = process.require('app/server/providers/UserProvider.js');
var RoleProvider = process.require('app/server/providers/RoleProvider.js');
var SettingProvider = process.require('app/server/providers/SettingProvider.js');
var storage = process.require('app/server/storage.js');
var ResourceFilter = openVeoApi.storages.ResourceFilter;
/**
* The authenticator helps manipulate users authenticated by passport strategies.
*
* Users returned by passport are not necessary OpenVeo users. It could be users from a third party authentication
* server. The authenticator helps making sure that the authenticated user is a ready to use OpenVeo user.
*
* @class authenticator
* @static
*/
/**
* Populates user with detailed roles and permissions.
*
* @method populateUser
* @async
* @param {Object} user The user to populate
* @param {Array} [user.roles] The list of role ids
* @param {Function} callback The function to call when it's done
* - **Error** The error if an error occurred, null otherwise
* - **Object** The populated user
*/
function populateUser(user, callback) {
if (!user.roles || !user.roles.length) return callback(null, user);
var roleProvider = new RoleProvider(storage.getDatabase());
roleProvider.get(
new ResourceFilter().in('id', user.roles),
null,
user.roles.length,
null,
{
name: 'asc'
},
function(error, roles) {
if (error) return callback(error);
user.permissions = [];
for (var i = 0; i < roles.length; i++)
user.permissions = openVeoApi.util.joinArray(user.permissions, roles[i].permissions);
user.roles = roles;
callback(null, user);
}
);
}
/**
* Serializes only essential user information required to retrieve it later.
*
* @method serializeUser
* @async
* @static
* @param {Object} user The user to serialize
* @param {Function} callback The function to call when it's done
* - **Error** The error if an error occurred, null otherwise
* - **String** The serialized user information
*/
module.exports.serializeUser = function(user, callback) {
if (!user || !user.id)
return callback(new Error('Could not serialize user: unknown user "' + (user ? user.id : '') + '"'));
callback(null, user.id);
};
/**
* Fetches a user with its permissions from serialized data.
*
* @method deserializeUser
* @async
* @static
* @param {String} data Serialized data as serialized by serializeUser(): the id of the user
* @param {Function} callback The function to call when it's done
* - **Error** The error if an error occurred, null otherwise
* - **Object** The user with its permissions
*/
module.exports.deserializeUser = function(data, callback) {
var userProvider = new UserProvider(storage.getDatabase());
userProvider.getOne(
new ResourceFilter().equal('id', data),
null,
function(error, user) {
if (error) return callback(error);
if (!user) return callback(new Error('Unkown user "' + data + '"'));
if (user.id === process.api.getCoreApi().getSuperAdminId()) return callback(null, user);
// Get user permissions and roles
populateUser(user, callback);
}
);
};
/**
* Verifies a user as returned by the passport local strategy.
*
* @method verifyUserByCredentials
* @async
* @static
* @param {String} email User email
* @param {String} password User password
* @param {Function} callback Function to call when its done
* - **Error** An error if something went wrong, null otherwise
* - **Object** The user with its permissions
*/
module.exports.verifyUserByCredentials = function(email, password, callback) {
var userProvider = new UserProvider(storage.getDatabase());
userProvider.getUserByCredentials(email, password, function(error, user) {
if (error) return callback(error);
if (!user) return callback(new Error('Email and / or password incorrect for "' + email + '"'));
if (user.id === process.api.getCoreApi().getSuperAdminId()) return callback(null, user);
populateUser(user, callback);
});
};
/**
* Verifies user as returned by third party providers.
*
* OpenVeo trusts users from third party providers, if the user does not exist in OpenVeo
* it is created with minimum information.
*
* @method verifyUserAuthentication
* @async
* @static
* @param {Object} thirdPartyUser The user from the third party provider
* @param {String} strategy The id of the strategy
* @param {Function} callback Function to call when its done
* - **Error** An error if something went wrong, null otherwise
* - **Object** The user with its permissions
*/
module.exports.verifyUserAuthentication = function(thirdPartyUser, strategy, callback) {
var user;
var exists = false;
var roles = [];
var strategyConfiguration = storage.getConfiguration().auth[strategy];
var thirdPartyIdAttribute = strategyConfiguration.userIdAttribute;
var thirdPartyNameAttribute = strategyConfiguration.userNameAttribute;
var thirdPartyEmailAttribute = strategyConfiguration.userEmailAttribute;
var thirdPartyGroupAttribute = strategyConfiguration.userGroupAttribute;
var userProvider = new UserProvider(storage.getDatabase());
var settingProvider = new SettingProvider(storage.getDatabase());
var originId = openVeoApi.util.evaluateDeepObjectProperties(thirdPartyIdAttribute, thirdPartyUser).replace(/ /g, '');
var originGroups = openVeoApi.util.evaluateDeepObjectProperties(thirdPartyGroupAttribute, thirdPartyUser);
var thirdPartyUserName = openVeoApi.util.evaluateDeepObjectProperties(thirdPartyNameAttribute, thirdPartyUser);
var thirdPartyUserEmail = openVeoApi.util.evaluateDeepObjectProperties(thirdPartyEmailAttribute, thirdPartyUser);
originGroups = originGroups || [];
originGroups = (Array.isArray(originGroups)) ? originGroups : originGroups.split(',');
async.series([
// Test if user already exists in OpenVeo
function(callback) {
if (originId) {
userProvider.getOne(
new ResourceFilter().equal('origin', strategy).equal('originId', originId),
null,
function(error, fetchedUser) {
if (error) return callback(error);
if (fetchedUser) {
exists = true;
user = fetchedUser;
}
callback();
}
);
} else {
exists = false;
callback();
}
},
// Attribute OpenVeo roles depending on third party user group
// Matching is made in OpenVeo settings page
function(callback) {
if (!originGroups) return callback();
settingProvider.getOne(
new ResourceFilter().equal('id', 'core-' + strategy),
null,
function(error, settings) {
if (error) return callback(error);
if (settings && settings.value && settings.value.length) {
// Look for third party user group inside OpenVeo settings
settings.value.forEach(function(match) {
if (originGroups.indexOf(match.group) >= 0)
roles = roles.concat(match.roles);
});
}
callback();
}
);
},
// Create user if it does not exist yet
function(callback) {
if (exists) return callback();
userProvider.addThirdPartyUsers([
{
name: thirdPartyUserName,
email: thirdPartyUserEmail,
roles: roles,
origin: strategy,
originId: originId,
originGroups: originGroups
}
], function(error, total, addedUsers) {
if (addedUsers) user = addedUsers[0];
callback(error);
});
},
// Update user if information from third party provider have changed (name, email, group)
function(callback) {
if (user.name !== thirdPartyUserName ||
user.email !== thirdPartyUserEmail ||
!openVeoApi.util.areSameArrays(user.originGroups, originGroups) ||
!openVeoApi.util.areSameArrays(user.roles, roles)
) {
user.name = thirdPartyUserName;
user.email = thirdPartyUserEmail;
user.roles = roles;
user.originGroups = originGroups;
userProvider.updateThirdPartyUser(
new ResourceFilter().equal('id', user.id),
{
name: user.name,
email: user.email,
originGroups: user.originGroups,
roles: user.roles
},
strategy,
callback
);
} else
callback();
},
// Fetches the user with its permissions
function(callback) {
populateUser(user, callback);
}
], function(error, results) {
callback(error, user);
});
};