204 lines
5.6 KiB
JavaScript
204 lines
5.6 KiB
JavaScript
|
|
const SyncConnector = require('./sync-connector');
|
|
const nthash = require('smbhash').nthash;
|
|
const ldap = require('./ldapjs-extra');
|
|
const crypto = require('crypto');
|
|
|
|
class SyncLdap extends SyncConnector {
|
|
async init() {
|
|
let ldapConfig = await this.$.LdapConfig.findOne({
|
|
fields: ['host', 'rdn', 'password', 'baseDn', 'groupDn']
|
|
});
|
|
if (!ldapConfig) return false;
|
|
|
|
let client = ldap.createClient({
|
|
url: `ldap://${ldapConfig.host}:389`
|
|
});
|
|
|
|
let ldapPassword = Buffer
|
|
.from(ldapConfig.password, 'base64')
|
|
.toString('ascii');
|
|
await client.bind(ldapConfig.rdn, ldapPassword);
|
|
|
|
Object.assign(this, {
|
|
ldapConfig,
|
|
client
|
|
});
|
|
return true;
|
|
}
|
|
|
|
async deinit() {
|
|
if (this.client)
|
|
await this.client.unbind();
|
|
}
|
|
|
|
async sync(info, userName, password) {
|
|
let {
|
|
ldapConfig,
|
|
client,
|
|
} = this;
|
|
|
|
let {
|
|
user,
|
|
hasAccount,
|
|
extraParams,
|
|
accountConfig
|
|
} = info;
|
|
|
|
let res = await client.search(ldapConfig.baseDn, {
|
|
scope: 'sub',
|
|
attributes: ['userPassword', 'sambaNTPassword'],
|
|
filter: `&(uid=${userName})`
|
|
});
|
|
|
|
let oldUser;
|
|
await new Promise((resolve, reject) => {
|
|
res.on('error', reject);
|
|
res.on('searchEntry', e => oldUser = e.object);
|
|
res.on('end', resolve);
|
|
});
|
|
|
|
try {
|
|
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
|
await client.del(dn);
|
|
} catch (e) {
|
|
if (e.name !== 'NoSuchObjectError') throw e;
|
|
}
|
|
|
|
if (!hasAccount) {
|
|
console.log(` -> '${userName}' removed from LDAP`);
|
|
return;
|
|
}
|
|
|
|
let nickname = user.nickname || userName;
|
|
let nameArgs = nickname.trim().split(' ');
|
|
let sn = nameArgs.length > 1
|
|
? nameArgs.splice(1).join(' ')
|
|
: '-';
|
|
|
|
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
|
let newEntry = {
|
|
uid: userName,
|
|
objectClass: [
|
|
'inetOrgPerson',
|
|
'posixAccount',
|
|
'sambaSamAccount'
|
|
],
|
|
cn: nickname,
|
|
displayName: nickname,
|
|
givenName: nameArgs[0],
|
|
sn,
|
|
mail: extraParams.corporateMail,
|
|
preferredLanguage: user.lang,
|
|
homeDirectory: `${accountConfig.homedir}/${userName}`,
|
|
loginShell: accountConfig.shell,
|
|
uidNumber: extraParams.uidNumber,
|
|
gidNumber: accountConfig.idBase + user.roleFk,
|
|
sambaSID: '-'
|
|
};
|
|
|
|
if (password) {
|
|
let salt = crypto
|
|
.randomBytes(8)
|
|
.toString('base64');
|
|
|
|
let hash = crypto.createHash('sha1');
|
|
hash.update(password);
|
|
hash.update(salt, 'binary');
|
|
let digest = hash.digest('binary');
|
|
|
|
let ssha = Buffer
|
|
.from(digest + salt, 'binary')
|
|
.toString('base64');
|
|
|
|
Object.assign(newEntry, {
|
|
userPassword: `{SSHA}${ssha}`,
|
|
sambaNTPassword: nthash(password)
|
|
});
|
|
} else if (oldUser) {
|
|
Object.assign(newEntry, {
|
|
userPassword: oldUser.userPassword,
|
|
sambaNTPassword: oldUser.sambaNTPassword
|
|
});
|
|
}
|
|
|
|
for (let prop in newEntry) {
|
|
if (newEntry[prop] == null)
|
|
delete newEntry[prop];
|
|
}
|
|
|
|
await client.add(dn, newEntry);
|
|
}
|
|
|
|
async syncGroups(info, userName) {
|
|
let {
|
|
ldapConfig,
|
|
client
|
|
} = this;
|
|
|
|
let {
|
|
user,
|
|
hasAccount
|
|
} = info;
|
|
|
|
let res = await client.search(ldapConfig.groupDn, {
|
|
scope: 'sub',
|
|
attributes: ['dn'],
|
|
filter: `&(memberUid=${userName})(objectClass=posixGroup)`
|
|
});
|
|
|
|
let oldGroups = [];
|
|
await new Promise((resolve, reject) => {
|
|
res.on('error', reject);
|
|
res.on('searchEntry', e => oldGroups.push(e.object));
|
|
res.on('end', resolve);
|
|
});
|
|
|
|
let reqs = [];
|
|
for (let oldGroup of oldGroups) {
|
|
let change = new ldap.Change({
|
|
operation: 'delete',
|
|
modification: {memberUid: userName}
|
|
});
|
|
reqs.push(client.modify(oldGroup.dn, change));
|
|
}
|
|
await Promise.all(reqs);
|
|
|
|
if (hasAccount) {
|
|
let reqs = [];
|
|
for (let role of user.roles()) {
|
|
let change = new ldap.Change({
|
|
operation: 'add',
|
|
modification: {memberUid: userName}
|
|
});
|
|
let roleName = role.inherits().name;
|
|
let dn = `cn=${roleName},${ldapConfig.groupDn}`;
|
|
reqs.push(client.modify(dn, change));
|
|
}
|
|
await Promise.all(reqs);
|
|
}
|
|
}
|
|
|
|
async getUsers(usersToSync) {
|
|
let {
|
|
ldapConfig,
|
|
client
|
|
} = this;
|
|
|
|
let res = await client.search(ldapConfig.baseDn, {
|
|
scope: 'sub',
|
|
attributes: ['uid'],
|
|
filter: `uid=*`
|
|
});
|
|
|
|
await new Promise((resolve, reject) => {
|
|
res.on('error', reject);
|
|
res.on('searchEntry', e => usersToSync.add(e.object.uid));
|
|
res.on('end', resolve);
|
|
});
|
|
}
|
|
}
|
|
|
|
SyncConnector.connectors.push(SyncLdap);
|
|
module.exports = SyncLdap;
|