LDAP user sync only syncs changed attributes
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Juan Ferrer 2020-12-09 12:28:18 +01:00
parent 954ba0c69d
commit 6f6f23bec4
1 changed files with 95 additions and 48 deletions

View File

@ -35,14 +35,13 @@ module.exports = Self => {
accountConfig
} = this;
let newEntry;
let dn = `uid=${userName},${this.userDn}`;
if (info.hasAccount) {
let {user} = info;
let oldUser = await client.searchOne(this.userDn, {
scope: 'sub',
attributes: ['userPassword', 'sambaNTPassword'],
filter: `&(uid=${userName})`
});
@ -52,7 +51,7 @@ module.exports = Self => {
? nameArgs.splice(1).join(' ')
: '-';
newEntry = {
let newEntry = {
uid: userName,
objectClass: [
'inetOrgPerson',
@ -101,67 +100,115 @@ module.exports = Self => {
if (newEntry[prop] == null)
delete newEntry[prop];
}
if (oldUser) {
let changes = [];
let skipProps = new Set([
'dn',
'controls'
]);
for (let prop in oldUser) {
let deleteProp = !skipProps.has(prop)
&& !newEntry.hasOwnProperty(prop);
if (!deleteProp) continue;
changes.push(new ldap.Change({
operation: 'delete',
modification: {
[prop]: oldUser[prop]
}
}));
}
for (let prop in newEntry) {
if (this.isEqual(oldUser[prop], newEntry[prop]))
continue;
changes.push(new ldap.Change({
operation: 'replace',
modification: {
[prop]: newEntry[prop]
}
}));
}
if (changes.length)
await client.modify(dn, changes);
} else
await client.add(dn, newEntry);
} else {
try {
await client.del(dn);
console.log(` -> User '${userName}' removed from LDAP`);
} catch (e) {
if (e.name !== 'NoSuchObjectError') throw e;
}
}
},
// Remove and recreate (if applicable) user
let dn = `uid=${userName},${this.userDn}`;
let operation;
try {
await client.del(dn);
operation = 'delete';
} catch (e) {
if (e.name !== 'NoSuchObjectError') throw e;
}
if (info.hasAccount) {
await client.add(dn, newEntry);
operation = 'add';
}
if (operation === 'delete')
console.log(` -> User '${userName}' removed from LDAP`);
isEqual(a, b) {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length)
return false;
for (let element of a) {
if (b.indexOf(element) === -1)
return false;
}
return true;
} else
return a == b;
},
async syncUserGroups(userName, info) {
let {client} = this;
let {user} = info;
let groupDn = this.groupDn;
let opts = {
scope: 'sub',
attributes: ['dn'],
attributes: ['dn', 'cn'],
filter: `&(memberUid=${userName})(objectClass=posixGroup)`
};
let oldGroups = await client.searchAll(this.groupDn, opts);
let oldGroups = await client.searchAll(groupDn, opts);
let reqs = [];
for (let oldGroup of oldGroups) {
let change = new ldap.Change({
operation: 'delete',
modification: {memberUid: userName}
});
reqs.push(client.modify(oldGroup.dn, change));
let deleteGroups = [];
let addGroups = [];
if (info.hasAccount) {
let oldSet = new Set();
oldGroups.forEach(e => oldSet.add(e.cn));
let newSet = new Set();
user.roles().forEach(e => newSet.add(e.inherits().name));
for (let group of oldGroups) {
if (!newSet.has(group.cn))
deleteGroups.push(group.cn);
}
for (let role of user.roles()) {
if (!oldSet.has(role.inherits().name))
addGroups.push(role.inherits().name);
}
} else {
for (let group of oldGroups)
deleteGroups.push(group.cn);
}
await Promise.all(reqs);
if (!info.hasAccount) return;
for (let role of info.user.roles()) {
let roleName = role.inherits().name;
let dn = `cn=${roleName},${this.groupDn}`;
let change = new ldap.Change({
operation: 'add',
modification: {memberUid: userName}
});
try {
await client.modify(dn, change);
} catch (err) {
if (err.name !== 'NoSuchObjectError')
throw err;
async function applyOperations(groups, operation) {
for (let group of groups) {
try {
let dn = `cn=${group},${groupDn}`;
await client.modify(dn, new ldap.Change({
operation,
modification: {memberUid: userName}
}));
} catch (err) {
if (err.name !== 'NoSuchObjectError')
throw err;
}
}
}
await applyOperations(deleteGroups, 'delete');
await applyOperations(addGroups, 'add');
},
async getUsers(usersToSync) {