LDAP & Samba synchronization fixes + improvements
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
parent
5e5dcf26c6
commit
9b563cb8bf
|
@ -9,7 +9,7 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"required": true
|
"id": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -56,7 +56,8 @@
|
||||||
"roles": {
|
"roles": {
|
||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "RoleRole",
|
"model": "RoleRole",
|
||||||
"foreignKey": "role"
|
"foreignKey": "role",
|
||||||
|
"primaryKey": "roleFk"
|
||||||
},
|
},
|
||||||
"emailUser": {
|
"emailUser": {
|
||||||
"type": "hasOne",
|
"type": "hasOne",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE `account`.`roleRole`
|
||||||
|
ADD `id` INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
||||||
|
ADD PRIMARY KEY (`id`);
|
File diff suppressed because it is too large
Load Diff
|
@ -62,31 +62,27 @@ module.exports = Self => {
|
||||||
let roles = await $.Role.find({
|
let roles = await $.Role.find({
|
||||||
fields: ['id', 'name']
|
fields: ['id', 'name']
|
||||||
});
|
});
|
||||||
|
let roleRoles = await $.RoleRole.find({
|
||||||
|
fields: ['role', 'inheritsFrom']
|
||||||
|
});
|
||||||
|
let roleMap = toMap(roleRoles, e => {
|
||||||
|
return {key: e.inheritsFrom, val: e.role};
|
||||||
|
});
|
||||||
|
|
||||||
let accounts = await $.UserAccount.find({
|
let accounts = await $.UserAccount.find({
|
||||||
fields: ['id'],
|
fields: ['id'],
|
||||||
include: {
|
include: {
|
||||||
relation: 'user',
|
relation: 'user',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['name'],
|
fields: ['name', 'roleFk'],
|
||||||
include: {
|
where: {active: true}
|
||||||
relation: 'roles',
|
|
||||||
scope: {
|
|
||||||
fields: ['inheritsFrom']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
let accountMap = toMap(accounts, e => {
|
||||||
let map = new Map();
|
let user = e.user();
|
||||||
for (let account of accounts) {
|
return {key: user.roleFk, val: user.name};
|
||||||
let user = account.user();
|
});
|
||||||
for (let inherit of user.roles()) {
|
|
||||||
let roleId = inherit.inheritsFrom;
|
|
||||||
if (!map.has(roleId)) map.set(roleId, []);
|
|
||||||
map.get(roleId).push(user.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reqs = [];
|
reqs = [];
|
||||||
for (let role of roles) {
|
for (let role of roles) {
|
||||||
|
@ -96,8 +92,14 @@ module.exports = Self => {
|
||||||
gidNumber: accountConfig.idBase + role.id
|
gidNumber: accountConfig.idBase + role.id
|
||||||
};
|
};
|
||||||
|
|
||||||
let memberUid = map.get(role.id);
|
let memberUid = [];
|
||||||
if (memberUid) newEntry.memberUid = memberUid;
|
for (subrole of roleMap.get(role.id) || [])
|
||||||
|
memberUid = memberUid.concat(accountMap.get(subrole) || []);
|
||||||
|
|
||||||
|
if (memberUid.length) {
|
||||||
|
memberUid.sort((a, b) => a.localeCompare(b));
|
||||||
|
newEntry.memberUid = memberUid;
|
||||||
|
}
|
||||||
|
|
||||||
let dn = `cn=${role.name},${ldapConfig.groupDn}`;
|
let dn = `cn=${role.name},${ldapConfig.groupDn}`;
|
||||||
reqs.push(client.add(dn, newEntry));
|
reqs.push(client.add(dn, newEntry));
|
||||||
|
@ -112,3 +114,14 @@ module.exports = Self => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function toMap(array, fn) {
|
||||||
|
let map = new Map();
|
||||||
|
for (let item of array) {
|
||||||
|
let keyVal = fn(item);
|
||||||
|
let key = keyVal.key;
|
||||||
|
if (!map.has(key)) map.set(key, []);
|
||||||
|
map.get(key).push(keyVal.val);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
const ldap = require('../../util/ldapjs-extra');
|
||||||
|
const ssh = require('node-ssh');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('syncAll', {
|
||||||
|
description: 'Synchronizes user database with LDAP and Samba',
|
||||||
|
http: {
|
||||||
|
path: `/syncAll`,
|
||||||
|
verb: 'PATCH'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.syncAll = async function() {
|
||||||
|
let $ = Self.app.models;
|
||||||
|
let usersToSync = new Set();
|
||||||
|
|
||||||
|
// Database
|
||||||
|
|
||||||
|
let accounts = await $.UserAccount.find({
|
||||||
|
fields: ['id'],
|
||||||
|
include: {
|
||||||
|
relation: 'user',
|
||||||
|
scope: {
|
||||||
|
fields: ['name'],
|
||||||
|
where: {active: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let account of accounts)
|
||||||
|
usersToSync.add(account.user().name);
|
||||||
|
|
||||||
|
// LDAP
|
||||||
|
|
||||||
|
let ldapConfig = await $.LdapConfig.findOne({
|
||||||
|
fields: ['host', 'rdn', 'password', 'baseDn']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ldapConfig) {
|
||||||
|
let ldapClient = ldap.createClient({
|
||||||
|
url: `ldap://${ldapConfig.host}:389`
|
||||||
|
});
|
||||||
|
|
||||||
|
let ldapPassword = Buffer
|
||||||
|
.from(ldapConfig.password, 'base64')
|
||||||
|
.toString('ascii');
|
||||||
|
await ldapClient.bind(ldapConfig.rdn, ldapPassword);
|
||||||
|
|
||||||
|
res = await ldapClient.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);
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: Cannot disconnect, hangs on undind() call
|
||||||
|
// await ldapClient.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samba
|
||||||
|
|
||||||
|
let sambaConfig = await $.SambaConfig.findOne({
|
||||||
|
fields: ['host', 'sshUser', 'sshPass']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sambaConfig) {
|
||||||
|
let sshPassword = Buffer
|
||||||
|
.from(sambaConfig.sshPass, 'base64')
|
||||||
|
.toString('ascii');
|
||||||
|
|
||||||
|
let sshClient = new ssh.NodeSSH();
|
||||||
|
await sshClient.connect({
|
||||||
|
host: sambaConfig.host,
|
||||||
|
username: sambaConfig.sshUser,
|
||||||
|
password: sshPassword
|
||||||
|
});
|
||||||
|
|
||||||
|
let res = await sshClient.execCommand('samba-tool user list');
|
||||||
|
let users = res.stdout.split('\n');
|
||||||
|
for (let user of users) usersToSync.add(user.trim());
|
||||||
|
|
||||||
|
await sshClient.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Syncing
|
||||||
|
|
||||||
|
$.RoleInherit.sync();
|
||||||
|
|
||||||
|
let sync = await Self.syncInit();
|
||||||
|
for (let user of usersToSync.values()) {
|
||||||
|
try {
|
||||||
|
await Self.doSync(sync, user);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Self.syncDeinit(sync);
|
||||||
|
};
|
||||||
|
};
|
|
@ -19,7 +19,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
http: {
|
http: {
|
||||||
path: `/sync`,
|
path: `/:userName/sync`,
|
||||||
verb: 'PATCH'
|
verb: 'PATCH'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -35,45 +35,121 @@ module.exports = Self => {
|
||||||
|
|
||||||
if (user && isSync) return;
|
if (user && isSync) return;
|
||||||
|
|
||||||
let accountConfig;
|
let sync = await Self.syncInit();
|
||||||
let mailConfig;
|
try {
|
||||||
|
await Self.doSync(sync, userName, password);
|
||||||
|
} finally {
|
||||||
|
await Self.syncDeinit(sync);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Self.syncInit = async function() {
|
||||||
|
let $ = Self.app.models;
|
||||||
|
|
||||||
|
let accountConfig = await $.AccountConfig.findOne({
|
||||||
|
fields: ['homedir', 'shell', 'idBase']
|
||||||
|
});
|
||||||
|
let mailConfig = await $.MailConfig.findOne({
|
||||||
|
fields: ['domain']
|
||||||
|
});
|
||||||
|
|
||||||
|
// LDAP
|
||||||
|
|
||||||
|
let ldapClient;
|
||||||
|
let ldapConfig = await $.LdapConfig.findOne({
|
||||||
|
fields: ['host', 'rdn', 'password', 'baseDn', 'groupDn']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ldapConfig) {
|
||||||
|
ldapClient = ldap.createClient({
|
||||||
|
url: `ldap://${ldapConfig.host}:389`
|
||||||
|
});
|
||||||
|
|
||||||
|
let ldapPassword = Buffer
|
||||||
|
.from(ldapConfig.password, 'base64')
|
||||||
|
.toString('ascii');
|
||||||
|
await ldapClient.bind(ldapConfig.rdn, ldapPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samba
|
||||||
|
|
||||||
|
let sambaClient;
|
||||||
|
let sambaConfig = await $.SambaConfig.findOne({
|
||||||
|
fields: ['host', 'sshUser', 'sshPass']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sambaConfig) {
|
||||||
|
let sshPassword = Buffer
|
||||||
|
.from(sambaConfig.sshPass, 'base64')
|
||||||
|
.toString('ascii');
|
||||||
|
|
||||||
|
sambaClient = new ssh.NodeSSH();
|
||||||
|
await sambaClient.connect({
|
||||||
|
host: sambaConfig.host,
|
||||||
|
username: sambaConfig.sshUser,
|
||||||
|
password: sshPassword
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
accountConfig,
|
||||||
|
mailConfig,
|
||||||
|
ldapConfig,
|
||||||
|
ldapClient,
|
||||||
|
sambaClient
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Self.syncDeinit = async function(sync) {
|
||||||
|
// FIXME: Cannot disconnect, hangs on undind() call
|
||||||
|
// if (sync.ldapClient)
|
||||||
|
// await sync.ldapClient.unbind();
|
||||||
|
|
||||||
|
if (sync.sambaClient)
|
||||||
|
await sync.sambaClient.dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
Self.doSync = async function(sync, userName, password) {
|
||||||
|
let $ = Self.app.models;
|
||||||
|
let {
|
||||||
|
accountConfig,
|
||||||
|
mailConfig,
|
||||||
|
ldapConfig,
|
||||||
|
ldapClient,
|
||||||
|
sambaClient
|
||||||
|
} = sync;
|
||||||
|
|
||||||
|
let user = await $.Account.findOne({
|
||||||
|
where: {name: userName},
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'nickname',
|
||||||
|
'email',
|
||||||
|
'lang',
|
||||||
|
'roleFk',
|
||||||
|
'sync',
|
||||||
|
'active',
|
||||||
|
'created',
|
||||||
|
'bcryptPassword',
|
||||||
|
'updated'
|
||||||
|
],
|
||||||
|
include: {
|
||||||
|
relation: 'roles',
|
||||||
|
scope: {
|
||||||
|
include: {
|
||||||
|
relation: 'inherits',
|
||||||
|
scope: {
|
||||||
|
fields: ['name']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let extraParams;
|
let extraParams;
|
||||||
let hasAccount = false;
|
let hasAccount = false;
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
accountConfig = await $.AccountConfig.findOne({
|
|
||||||
fields: ['homedir', 'shell', 'idBase']
|
|
||||||
});
|
|
||||||
mailConfig = await $.MailConfig.findOne({
|
|
||||||
fields: ['domain']
|
|
||||||
});
|
|
||||||
|
|
||||||
user = await $.Account.findById(user.id, {
|
|
||||||
fields: [
|
|
||||||
'id',
|
|
||||||
'nickname',
|
|
||||||
'email',
|
|
||||||
'lang',
|
|
||||||
'roleFk',
|
|
||||||
'sync',
|
|
||||||
'active',
|
|
||||||
'created',
|
|
||||||
'updated'
|
|
||||||
],
|
|
||||||
where: {name: userName},
|
|
||||||
include: {
|
|
||||||
relation: 'roles',
|
|
||||||
scope: {
|
|
||||||
include: {
|
|
||||||
relation: 'inherits',
|
|
||||||
scope: {
|
|
||||||
fields: ['name']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
extraParams = {
|
extraParams = {
|
||||||
corporateMail: `${userName}@${mailConfig.domain}`,
|
corporateMail: `${userName}@${mailConfig.domain}`,
|
||||||
uidNumber: accountConfig.idBase + user.id
|
uidNumber: accountConfig.idBase + user.id
|
||||||
|
@ -83,8 +159,12 @@ module.exports = Self => {
|
||||||
&& await $.UserAccount.exists(user.id);
|
&& await $.UserAccount.exists(user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Database
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
let bcryptPassword = $.User.hashPassword(password);
|
let bcryptPassword = password
|
||||||
|
? $.User.hashPassword(password)
|
||||||
|
: user.bcryptPassword;
|
||||||
|
|
||||||
await $.Account.upsertWithWhere({id: user.id},
|
await $.Account.upsertWithWhere({id: user.id},
|
||||||
{bcryptPassword}
|
{bcryptPassword}
|
||||||
|
@ -101,7 +181,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
// SIP
|
// SIP
|
||||||
|
|
||||||
if (hasAccount) {
|
if (hasAccount && password) {
|
||||||
await Self.rawSql('CALL pbx.sip_setPassword(?, ?)',
|
await Self.rawSql('CALL pbx.sip_setPassword(?, ?)',
|
||||||
[user.id, password]
|
[user.id, password]
|
||||||
);
|
);
|
||||||
|
@ -109,155 +189,169 @@ module.exports = Self => {
|
||||||
|
|
||||||
// LDAP
|
// LDAP
|
||||||
|
|
||||||
let ldapConfig = await $.LdapConfig.findOne({
|
if (ldapClient) {
|
||||||
fields: ['host', 'rdn', 'password', 'baseDn', 'groupDn']
|
// Deletes user
|
||||||
});
|
|
||||||
|
|
||||||
if (ldapConfig) {
|
res = await ldapClient.search(ldapConfig.baseDn, {
|
||||||
let ldapClient = ldap.createClient({
|
scope: 'sub',
|
||||||
url: `ldap://${ldapConfig.host}:389`
|
attributes: ['userPassword', 'sambaNTPassword'],
|
||||||
|
filter: `&(uid=${userName})(objectClass=inetOrgPerson)`
|
||||||
});
|
});
|
||||||
|
|
||||||
let ldapPassword = Buffer
|
let oldUser;
|
||||||
.from(ldapConfig.password, 'base64')
|
await new Promise((resolve, reject) => {
|
||||||
.toString('ascii');
|
res.on('error', reject);
|
||||||
await ldapClient.bind(ldapConfig.rdn, ldapPassword);
|
res.on('searchEntry', e => oldUser = e.object);
|
||||||
|
res.on('end', resolve);
|
||||||
|
});
|
||||||
|
|
||||||
let err;
|
|
||||||
try {
|
try {
|
||||||
// Deletes user
|
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
||||||
|
await ldapClient.del(dn);
|
||||||
try {
|
|
||||||
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
|
||||||
await ldapClient.del(dn);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.name !== 'NoSuchObjectError') throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes user from groups
|
|
||||||
|
|
||||||
let opts = {
|
|
||||||
scope: 'sub',
|
|
||||||
attributes: ['dn'],
|
|
||||||
filter: `&(memberUid=${userName})(objectClass=posixGroup)`
|
|
||||||
};
|
|
||||||
res = await ldapClient.search(ldapConfig.groupDn, opts);
|
|
||||||
|
|
||||||
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 (oldGroup of oldGroups) {
|
|
||||||
let change = new ldap.Change({
|
|
||||||
operation: 'delete',
|
|
||||||
modification: {memberUid: userName}
|
|
||||||
});
|
|
||||||
reqs.push(ldapClient.modify(oldGroup.dn, change));
|
|
||||||
}
|
|
||||||
await Promise.all(reqs);
|
|
||||||
|
|
||||||
if (hasAccount) {
|
|
||||||
// Recreates user
|
|
||||||
|
|
||||||
let nameArgs = user.nickname.split(' ');
|
|
||||||
let sshaPassword = crypto
|
|
||||||
.createHash('sha1')
|
|
||||||
.update(password)
|
|
||||||
.digest('base64');
|
|
||||||
|
|
||||||
let dn = `uid=${userName},${ldapConfig.baseDn}`;
|
|
||||||
let newEntry = {
|
|
||||||
uid: userName,
|
|
||||||
objectClass: [
|
|
||||||
'inetOrgPerson',
|
|
||||||
'posixAccount',
|
|
||||||
'sambaSamAccount'
|
|
||||||
],
|
|
||||||
cn: user.nickname || userName,
|
|
||||||
displayName: user.nickname,
|
|
||||||
givenName: nameArgs[0],
|
|
||||||
sn: nameArgs[1] || 'Empty',
|
|
||||||
mail: extraParams.corporateMail,
|
|
||||||
userPassword: `{SSHA}${sshaPassword}`,
|
|
||||||
preferredLanguage: user.lang,
|
|
||||||
homeDirectory: `${accountConfig.homedir}/${userName}`,
|
|
||||||
loginShell: accountConfig.shell,
|
|
||||||
uidNumber: extraParams.uidNumber,
|
|
||||||
gidNumber: accountConfig.idBase + user.roleFk,
|
|
||||||
sambaSID: '-',
|
|
||||||
sambaNTPassword: nthash(password)
|
|
||||||
};
|
|
||||||
await ldapClient.add(dn, newEntry);
|
|
||||||
|
|
||||||
// Adds user to groups
|
|
||||||
|
|
||||||
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(ldapClient.modify(dn, change));
|
|
||||||
}
|
|
||||||
await Promise.all(reqs);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e;
|
if (e.name !== 'NoSuchObjectError') throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Cannot disconnect, hangs on undind() call
|
// Removes user from groups
|
||||||
// await ldapClient.unbind();
|
|
||||||
if (err) throw err;
|
res = await ldapClient.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 (oldGroup of oldGroups) {
|
||||||
|
let change = new ldap.Change({
|
||||||
|
operation: 'delete',
|
||||||
|
modification: {memberUid: userName}
|
||||||
|
});
|
||||||
|
reqs.push(ldapClient.modify(oldGroup.dn, change));
|
||||||
|
}
|
||||||
|
await Promise.all(reqs);
|
||||||
|
|
||||||
|
if (hasAccount) {
|
||||||
|
// Recreates user
|
||||||
|
|
||||||
|
let nameArgs = user.nickname.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: user.nickname || userName,
|
||||||
|
displayName: user.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: '-'
|
||||||
|
};
|
||||||
|
|
||||||
|
let passwords;
|
||||||
|
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');
|
||||||
|
|
||||||
|
passwords = {
|
||||||
|
userPassword: `{SSHA}${ssha}`,
|
||||||
|
sambaNTPassword: nthash(password)
|
||||||
|
};
|
||||||
|
} else if (oldUser) {
|
||||||
|
passwords = {
|
||||||
|
userPassword: oldUser.userPassword,
|
||||||
|
sambaNTPassword: oldUser.sambaNTPassword
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passwords)
|
||||||
|
Object.assign(newEntry, passwords);
|
||||||
|
|
||||||
|
await ldapClient.add(dn, newEntry);
|
||||||
|
|
||||||
|
// Adds user to groups
|
||||||
|
|
||||||
|
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(ldapClient.modify(dn, change));
|
||||||
|
}
|
||||||
|
await Promise.all(reqs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Samba
|
// Samba
|
||||||
|
|
||||||
let sambaConfig = await $.SambaConfig.findOne({
|
if (sambaClient) {
|
||||||
fields: ['host', 'sshUser', 'sshPass']
|
|
||||||
});
|
|
||||||
|
|
||||||
if (sambaConfig) {
|
|
||||||
let sshPassword = Buffer
|
|
||||||
.from(sambaConfig.sshPass, 'base64')
|
|
||||||
.toString('ascii');
|
|
||||||
|
|
||||||
let sshClient = new ssh.NodeSSH();
|
|
||||||
await sshClient.connect({
|
|
||||||
host: sambaConfig.host,
|
|
||||||
username: sambaConfig.sshUser,
|
|
||||||
password: sshPassword
|
|
||||||
});
|
|
||||||
|
|
||||||
let commands;
|
|
||||||
|
|
||||||
if (hasAccount) {
|
if (hasAccount) {
|
||||||
commands = [
|
try {
|
||||||
`samba-tool user create "${userName}" `
|
await sambaClient.exec('samba-tool user create', [
|
||||||
+ `--uid-number=${extraParams.uidNumber} `
|
userName,
|
||||||
+ `--mail-address="${extraParams.corporateMail}" `
|
'--uid-number', `${extraParams.uidNumber}`,
|
||||||
+ `--random-password`,
|
'--mail-address', extraParams.corporateMail,
|
||||||
`samba-tool user setexpiry "${userName}" `
|
'--random-password'
|
||||||
+ `--noexpiry`,
|
]);
|
||||||
`samba-tool user setpassword "${userName}" `
|
} catch (e) {}
|
||||||
+ `--newpassword="${password}"`,
|
|
||||||
`mkhomedir_helper "${userName}" 0027`
|
await sambaClient.exec('samba-tool user setexpiry', [
|
||||||
];
|
userName,
|
||||||
|
'--noexpiry'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (password) {
|
||||||
|
await sambaClient.exec('samba-tool user setpassword', [
|
||||||
|
userName,
|
||||||
|
'--newpassword', password
|
||||||
|
]);
|
||||||
|
await sambaClient.exec('samba-tool user enable', [
|
||||||
|
userName
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
await sambaClient.exec('mkhomedir_helper', [
|
||||||
|
userName,
|
||||||
|
'0027'
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
commands = [
|
try {
|
||||||
`samba-tool user delete "${userName}"`
|
await sambaClient.exec('samba-tool user disable', [
|
||||||
];
|
userName
|
||||||
|
]);
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let command of commands)
|
|
||||||
await sshClient.execCommand(command);
|
|
||||||
|
|
||||||
await sshClient.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark as synchronized
|
// Mark as synchronized
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"role": {
|
"id": {
|
||||||
"id": true
|
"id": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,4 +2,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/user-account/sync')(Self);
|
require('../methods/user-account/sync')(Self);
|
||||||
require('../methods/user-account/sync-by-id')(Self);
|
require('../methods/user-account/sync-by-id')(Self);
|
||||||
|
require('../methods/user-account/sync-all')(Self);
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue