initial files
This commit is contained in:
258
src/services/activeDirectoryManager.js
Normal file
258
src/services/activeDirectoryManager.js
Normal file
@@ -0,0 +1,258 @@
|
||||
const ActiveDirectory = require('activedirectory2');
|
||||
|
||||
class ActiveDirectoryManager {
|
||||
constructor({
|
||||
url,
|
||||
baseDN,
|
||||
username,
|
||||
password,
|
||||
userAttributes,
|
||||
groupAttributes,
|
||||
computerAttributes
|
||||
}) {
|
||||
this.ad = new ActiveDirectory({
|
||||
url,
|
||||
baseDN,
|
||||
username,
|
||||
password,
|
||||
attributes: {
|
||||
user: userAttributes,
|
||||
group: groupAttributes,
|
||||
computer: computerAttributes
|
||||
}
|
||||
});
|
||||
|
||||
this.userAttributes = userAttributes;
|
||||
this.groupAttributes = groupAttributes;
|
||||
this.computerAttributes = computerAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* INTERNAL GENERIC LDAP SEARCH
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
async ldapSearch(options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ad.find(options, (err, result) => {
|
||||
if (err) return reject(err);
|
||||
resolve(result || {});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* USER FUNCTIONS
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
async getUser(username, attributes = this.userAttributes) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ad.findUser({ attributes }, username, (err, user) => {
|
||||
if (err) return reject(err);
|
||||
resolve(user || null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async getUserDN(username) {
|
||||
const user = await this.getUser(username);
|
||||
return user?.dn || null;
|
||||
}
|
||||
|
||||
async findUsers(query, attributes = this.userAttributes) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const filter = `(&(objectClass=user)(|(cn=${query})(sAMAccountName=${query})(mail=${query})(displayName=${query})))`;
|
||||
|
||||
this.ad.findUsers({ filter, attributes }, (err, users) => {
|
||||
if (err) return reject(err);
|
||||
resolve(users || []);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* GROUP FUNCTIONS
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
async getGroup(groupName, attributes = this.groupAttributes) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ad.findGroup({ attributes }, groupName, (err, group) => {
|
||||
if (err) return reject(err);
|
||||
resolve(group || null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async findGroups(query, attributes = this.groupAttributes) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const filter = `(&(objectClass=group)(cn=${query}))`;
|
||||
|
||||
this.ad.findGroups({ filter, attributes }, (err, groups) => {
|
||||
if (err) return reject(err);
|
||||
resolve(groups || []);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* COMPUTER / OU FUNCTIONS 🖥️
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Einzelnen Computer holen
|
||||
*/
|
||||
async getComputer(name, attributes = this.computerAttributes) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const filter = `(&(objectClass=computer)(|(cn=${name})(dNSHostName=${name})))`;
|
||||
|
||||
this.ad.find({ filter, attributes }, (err, result) => {
|
||||
if (err) return reject(err);
|
||||
resolve(result?.other?.[0] || null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alle Computer
|
||||
*/
|
||||
async getComputers(attributes = this.computerAttributes) {
|
||||
const options = {
|
||||
baseDN: this.ad.baseDN,
|
||||
filter: '(objectClass=computer)',
|
||||
attributes
|
||||
};
|
||||
|
||||
const result = await this.ldapSearch(options);
|
||||
return result.other || [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alle Computer aus einer OU holen
|
||||
*/
|
||||
async getComputersFromOU(ouDn, attributes = this.computerAttributes) {
|
||||
const options = {
|
||||
baseDN: ouDn,
|
||||
filter: '(objectClass=computer)',
|
||||
attributes
|
||||
};
|
||||
|
||||
const result = await this.ldapSearch(options);
|
||||
return result.other || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Computer suchen (Wildcard möglich)
|
||||
* Beispiele: "PC-*", "*LAPTOP*", "SRV01"
|
||||
*/
|
||||
async findComputers(query, attributes = this.computerAttributes) {
|
||||
const filter = `(&(objectClass=computer)(|(cn=${query})(dNSHostName=${query})))`;
|
||||
|
||||
const result = await this.ldapSearch({
|
||||
filter,
|
||||
attributes
|
||||
});
|
||||
return result.other || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* GROUP MEMBERSHIP (DIRECT & RECURSIVE)
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
async isUserMemberOfDirect(username, groupName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ad.isUserMemberOf(username, groupName, (err, isMember) => {
|
||||
if (err) return reject(err);
|
||||
resolve(isMember);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async isUserMemberOfRecursive(username, groupName, visited = new Set()) {
|
||||
const key = groupName.toLowerCase();
|
||||
if (visited.has(key)) return false;
|
||||
visited.add(key);
|
||||
|
||||
const direct = await this.isUserMemberOfDirect(username, groupName);
|
||||
if (direct) return true;
|
||||
|
||||
const group = await this.getGroup(groupName);
|
||||
if (!group || !Array.isArray(group.member)) return false;
|
||||
|
||||
for (const dn of group.member) {
|
||||
const match = dn.match(/CN=([^,]+)/i);
|
||||
if (!match) continue;
|
||||
|
||||
const subGroupName = match[1];
|
||||
const found = await this.isUserMemberOfRecursive(username, subGroupName, visited);
|
||||
if (found) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async getGroupSubgroups(groupName, visited = new Set()) {
|
||||
const key = groupName.toLowerCase();
|
||||
if (visited.has(key)) return [];
|
||||
|
||||
visited.add(key);
|
||||
|
||||
const group = await this.getGroup(groupName);
|
||||
if (!group || !Array.isArray(group.member)) return [];
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const memberDN of group.member) {
|
||||
const match = memberDN.match(/CN=([^,]+)/i);
|
||||
if (!match) continue;
|
||||
|
||||
const subGroupName = match[1];
|
||||
const sub = await this.getGroup(subGroupName).catch(() => null);
|
||||
if (!sub) continue;
|
||||
|
||||
results.push(sub);
|
||||
results.push(...await this.getGroupSubgroups(subGroupName, visited));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async getGroupRecursive(groupName, visited = new Set()) {
|
||||
const key = groupName.toLowerCase();
|
||||
if (visited.has(key)) return null;
|
||||
|
||||
visited.add(key);
|
||||
|
||||
const group = await this.getGroup(groupName);
|
||||
if (!group) return null;
|
||||
|
||||
const result = {
|
||||
...group,
|
||||
subgroups: []
|
||||
};
|
||||
|
||||
if (!Array.isArray(group.member)) return result;
|
||||
|
||||
for (const memberDN of group.member) {
|
||||
const match = memberDN.match(/CN=([^,]+)/i);
|
||||
if (!match) continue;
|
||||
|
||||
const subGroupName = match[1];
|
||||
const subTree = await this.getGroupRecursive(subGroupName, visited);
|
||||
if (subTree) result.subgroups.push(subTree);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ActiveDirectoryManager;
|
||||
Reference in New Issue
Block a user