WIP: #5770 - Sync Groups Samba #1946

Draft
jsegarra wants to merge 38 commits from 5770_sambaGroups into dev
2 changed files with 81 additions and 48 deletions
Showing only changes of commit 117f42ff96 - Show all commits

View File

@ -3793,4 +3793,4 @@ INSERT INTO vn.workCenter (id, name, payrollCenterFk, counter, warehouseFk, stre
INSERT INTO account.sambaConfig (id,adDomain,adController,adUser,adPassword,verifyCert,userDn,groupDn) VALUES INSERT INTO account.sambaConfig (id,adDomain,adController,adUser,adPassword,verifyCert,userDn,groupDn) VALUES
(1,'verdnatura.es','192.168.56.102','Administrator','V3rdn4tur4$',0,'ou=VnUsers','ou=VnGroups'); (1,'verdnatura.es','192.168.56.101','Administrator','V3rdn4tur4$',0,'ou=VnUsers','ou=VnGroups');

View File

@ -2,7 +2,7 @@ const app = require('vn-loopback/server/server');
const ldap = require('../util/ldapjs-extra'); const ldap = require('../util/ldapjs-extra');
const {differences, toMap, printResults} = require('../util/helpers'); const {differences, toMap, printResults} = require('../util/helpers');
const execFile = require('child_process').execFile; const execFile = require('child_process').execFile;
// const ROLE_PREFIX = 'VN_'; const ROLE_PREFIX = '$';
/** /**
* Summary of userAccountControl flags: * Summary of userAccountControl flags:
* https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties * https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties
@ -172,7 +172,25 @@ module.exports = Self => {
await this.adClient.searchForeach(this.fullUsersDn, opts, await this.adClient.searchForeach(this.fullUsersDn, opts,
o => usersToSync.add(o.sAMAccountName)); o => usersToSync.add(o.sAMAccountName));
}, },
deleteRole(role) {
return this.sambaTool('group', ['delete', role]);
},
addRole({description, name}) {
return this.sambaTool('group',
['add', `${ROLE_PREFIX}${name}`, `--groupou=${this.groupDn}`, `--description=${description}`]);
},
getRoleMembers(role) {
return this.getMembers(`(cn=${role})`, this.fullGroupsDn);
},
getMembers(filter = '', type = this.fullUsersDn) {
const options = {
scope: 'sub',
attributes: ['cn', 'member', 'member.cn']
};
if (filter !== '')
Object.assign(options, {filter});
return this.adClient.searchAll(type, options);
},
async syncRoles() { async syncRoles() {
await this.init(); await this.init();
let $ = app.models; let $ = app.models;
@ -184,49 +202,44 @@ module.exports = Self => {
// Prepare data // Prepare data
try { try {
// const filter = '(cn=VN_*)'; // const filter = '(cn=VN_*)';
const scope = 'sub';
// const baseDN = 'cn=Users,dc=verdnatura,dc=es'; // const baseDN = 'cn=Users,dc=verdnatura,dc=es';
// const ldapMembersGroups = await this.adClient.searchAll(baseDN, { const ldapMembersGroups = await this.getMembers();
// scope,
// attributes: ['cn', 'member'],
// filter
// });
// OBTENER ROLES // OBTENER ROLES
let roles = (await $.VnRole.find({ let roles = (await $.VnRole.find({
fields: ['id', 'name', 'description'], fields: ['id', 'name', 'description'],
order: 'modified DESC', order: 'modified DESC',
limit: 1 limit: 2
})); })).reduce((map, role) => {
map.set(`${ROLE_PREFIX}${role.name}`, role);
let rolesName = roles.map(role => role.name); return map;
}, new Map());
const rolesKeys = Array.from(roles.keys());
// OBTENER LDAPSJS ROLES // OBTENER LDAPSJS ROLES
const ldapGroups = (await this.adClient.searchAll(baseDN, { const ldapGroups = await this.adClient.searchAll(this.fullGroupsDn, {
scope, scope: 'sub',
attributes: ['cn', 'description'], attributes: ['cn', 'description'],
}));/* , (err, res)=>{ });
res.on('searchEntry', entry=>{
console.log(entry)
})
res.on('error', entry=>{
console.log(entry)
})
res.on('end', entry=>{
console.log(entry)
})
})*/
// OBTENER SAMBA ROLES // OBTENER SAMBA ROLES
let sambaCurrentRoles = ldapGroups.map(({cn}) => cn); let sambaCurrentGroups = ldapGroups
.filter(group => Object.prototype.hasOwnProperty.call(group, 'cn'))
.reduce((map, group) => {
map.set(`${group.cn}`, group);
return map;
}, new Map());
const sambaRolesKeys = Array.from(sambaCurrentGroups.keys());// .map(({cn}) => cn);
// handleExecResponse(await this.sambaTool('group', ['list'])) // handleExecResponse(await this.sambaTool('group', ['list']))
// .filter(group => group.startsWith(ROLE_PREFIX)); // .filter(group => group.startsWith(ROLE_PREFIX));
// Encontrar elementos a eliminar // Encontrar elementos a eliminar
const rolesToDelete = differences(sambaCurrentRoles, rolesName); const rolesToDelete = differences(sambaRolesKeys, rolesKeys);
// Encontrar elementos a insertar // Encontrar elementos a insertar
const rolesToInsert = differences(roles, sambaCurrentRoles); const rolesToInsert = differences(rolesKeys, sambaRolesKeys);
// Encontrar elementos a actualizar // Encontrar elementos a actualizar
const rolesToUpdate = differences(roles, [...rolesToDelete, ...rolesToInsert]); const rolesToUpdate = differences(rolesKeys, [...rolesToDelete, ...rolesToInsert]);
// OBTENER USUARIOS Y SUS ROLES // OBTENER USUARIOS Y SUS ROLES
if ( if (
@ -249,7 +262,7 @@ module.exports = Self => {
console.info(`User ${user.name} has not valid role`); console.info(`User ${user.name} has not valid role`);
return; return;
} }
return {key: role.name, val: user.name}; return {key: `${ROLE_PREFIX}${role.name}`, val: user.name};
}); });
usersMap.set('group1', ['employee']); usersMap.set('group1', ['employee']);
if (rolesToDelete.length > 0) { if (rolesToDelete.length > 0) {
@ -269,7 +282,7 @@ module.exports = Self => {
// PROCEDIMIENTO PARA ELIMINAR ROLES // PROCEDIMIENTO PARA ELIMINAR ROLES
const resultsRoleDelete = await Promise.all( const resultsRoleDelete = await Promise.all(
rolesToDelete.map(role => this.sambaTool('group', ['delete', role])) rolesToDelete.map(this.deleteRole)
); );
printResults(resultsRoleDelete); printResults(resultsRoleDelete);
} }
@ -277,16 +290,12 @@ module.exports = Self => {
if (rolesToInsert.length > 0) { if (rolesToInsert.length > 0) {
// PROCEDIMIENTO PARA INSERTAR ROLES // PROCEDIMIENTO PARA INSERTAR ROLES
const resultsRoleInsert = await Promise.all( const resultsRoleInsert = await Promise.all(
rolesToInsert.map( rolesToInsert.map(role => this.addRole(roles.get(role))));
({description, name}) =>
this.sambaTool('group',
['add', name, `--groupou=${this.groupDN}`, `--description="${description}"`]))
);
printResults(resultsRoleInsert); printResults(resultsRoleInsert);
// PROCEDIMIENTO PARA INSERTAR USUARIOS ASOCIADOS AL ROL // PROCEDIMIENTO PARA INSERTAR USUARIOS ASOCIADOS AL ROL
let usersToGroup = rolesToInsert.flatMap(role => usersMap.get(role.name).map( let usersToGroup = rolesToInsert.flatMap(role => usersMap.get(role).map(
a => this.sambaTool('group', ['addmembers', role.name, a]) a => this.sambaTool('group', ['addmembers', role, a])
) )
); );
const resultsUserGroup = await Promise.all(usersToGroup); const resultsUserGroup = await Promise.all(usersToGroup);
@ -298,21 +307,45 @@ module.exports = Self => {
// OBTENER LDAPSJS MIEMBROS ROLES // OBTENER LDAPSJS MIEMBROS ROLES
for await (const role of rolesToUpdate) { for await (const role of rolesToUpdate) {
const users = await this.sambaTool('group', ['listmembers', role]); let roleHasUpdated = false;
const usersToDelete = differences(users, usersMap.get(role)); if (roles.get(role).$description != sambaCurrentGroups.get(role).description) {
promises.push(usersToDelete.map(user => await this.deleteRole(role);
this.sambaTool('group', ['removemembers', user.name]))); await this.addRole(roles.get(role));
const usersToInsert = differences(usersMap.get(role), users); roleHasUpdated = true;
promises.push(usersToInsert.map(user => }
this.sambaTool('group', ['addmembers', role.name, user.name]))); const users = usersMap.get(role);
const currentUsers = this.handleRoleMembers(await this.getRoleMembers(role));
await Promise.all(promises); if (!roleHasUpdated && currentUsers.length === 0 && users.length === 0) continue;
await this.handleUsersRole(role, currentUsers, users);
} }
} }
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
},
handleRoleMembers(users) {
if (users.length === 0) return [];
let members = users[0]?.member;
if (!members) return [];
if (!Array.isArray(members))members = [members];
return members.map((member => member.match(/CN=(.*?),(.*)/)[1]));
},
async handleUsersRole(role, currentUsers, users) {
const forbiddenUsers = ['guest'];
users = users.filter(u => !u.includes(forbiddenUsers));
const usersToDelete = differences(currentUsers, users);
if (usersToDelete.length > 0) {
const results = await Promise.all(usersToDelete.map(user =>
this.sambaTool('group', ['removemembers', role, user])));
printResults(results);
}
const usersToInsert = differences(users, currentUsers);
if (usersToInsert.length > 0) {
const results = await Promise.all(usersToInsert.map(user =>
this.sambaTool('group', ['addmembers', role, user])));
printResults(results);
}
} }
}); });