133 lines
5.5 KiB
JavaScript
133 lines
5.5 KiB
JavaScript
/**
|
|
* AD/LDAP routes module.
|
|
*/
|
|
const express = require('express');
|
|
const { authMiddleware, adminMiddleware } = require('../middleware/auth');
|
|
const { auditLog } = require('../auditLog');
|
|
const { isLDAPConfigured } = require('../ldapSync');
|
|
const { browseOUTree, createADUser, checkADUserExists, deleteADUser } = require('../ldapOperations');
|
|
const { searchADGroups, addUserToGroups, browseADGroups } = require('../ldapOperations');
|
|
const { validate, createADUserSchema, deleteADUserSchema } = require('../middleware/validation');
|
|
const { toSamAccountName } = require('../umlauts');
|
|
|
|
const router = express.Router();
|
|
|
|
// LDAP Status Endpoint (public)
|
|
router.get('/status', (req, res) => {
|
|
res.json({ configured: isLDAPConfigured() });
|
|
});
|
|
|
|
// All other AD routes require auth
|
|
router.use(authMiddleware);
|
|
|
|
// Browse OU tree
|
|
router.get('/ou-tree', (req, res) => {
|
|
const { base } = req.query;
|
|
browseOUTree(base || undefined).then(ous => {
|
|
res.json(ous);
|
|
}).catch(err => {
|
|
console.error('[ERROR] GET /ad/ou-tree -', err.message);
|
|
res.status(500).json({ error: 'Interner Serverfehler.' });
|
|
});
|
|
});
|
|
|
|
// Search AD groups (all security groups)
|
|
router.get('/groups', (req, res) => {
|
|
const { q } = req.query;
|
|
if (!q || q.trim().length < 2) {
|
|
return res.json([]);
|
|
}
|
|
searchADGroups(q.trim()).then(groups => {
|
|
res.json(groups);
|
|
}).catch(err => {
|
|
console.error('[ERROR] GET /ad/groups -', err.message);
|
|
res.status(500).json({ error: 'Interner Serverfehler.' });
|
|
});
|
|
});
|
|
|
|
// Browse all AD groups (for tree display)
|
|
router.get('/groups-tree', (req, res) => {
|
|
browseADGroups().then(groups => {
|
|
res.json(groups);
|
|
}).catch(err => {
|
|
console.error('[ERROR] GET /ad/groups-tree -', err.message);
|
|
res.status(500).json({ error: 'Interner Serverfehler.' });
|
|
});
|
|
});
|
|
|
|
// Get AD create config
|
|
router.get('/create-config', (req, res) => {
|
|
res.json({
|
|
configured: isLDAPConfigured(),
|
|
createOU: process.env.LDAP_CREATE_OU || '',
|
|
upnSuffix: process.env.LDAP_UPN_SUFFIX || process.env.LDAP_BIND_USER?.split('@')[1] || '',
|
|
});
|
|
});
|
|
|
|
// Create AD user (admin only)
|
|
router.post('/create-user', adminMiddleware, validate(createADUserSchema), async (req, res) => {
|
|
const { ou, vorname, nachname, email, username, password, department, telefon, titel, displayName, physicalDeliveryOfficeName, company, description, wWWHomePage, streetAddress, postOfficeBox, l, st, postalCode, c, groups } = req.validatedBody;
|
|
|
|
try {
|
|
// FIX: Umlaute zentral transliterieren (ä→ae etc.) — galt vorher nur für
|
|
// nachname/vorname einzeln; jetzt einheitlich über umlauts.js. Der Username
|
|
// (und damit UPN) wird ebenfalls umlautfrei normalisiert.
|
|
let sAMAccountName = toSamAccountName(username);
|
|
if (vorname && nachname) {
|
|
sAMAccountName = toSamAccountName(nachname + vorname.charAt(0));
|
|
}
|
|
sAMAccountName = sAMAccountName.substring(0, 20);
|
|
|
|
// Fallback: Wenn der Name nur aus Sonderzeichen bestand (z.B. rein chinesisch),
|
|
// wäre sAMAccountName leer — AD würde den User ablehnen. Dann generischen
|
|
// Namen aus Zeitstempel verwenden und den Original-Username als displayName behalten.
|
|
if (!sAMAccountName) {
|
|
sAMAccountName = 'user' + Date.now().toString(36);
|
|
console.warn('[AD] sAMAccountName war nach Normalisierung leer — Fallback:', sAMAccountName);
|
|
}
|
|
|
|
const existing = await checkADUserExists(username, sAMAccountName);
|
|
if (existing) {
|
|
return res.status(409).json({ error: 'Benutzername "' + username + '" existiert bereits im Active Directory.', dn: existing.distinguishedName });
|
|
}
|
|
|
|
const result = await createADUser({ ou, vorname, nachname, email, username, password, department, telefon, titel, displayName, physicalDeliveryOfficeName, company, description, wWWHomePage, streetAddress, postOfficeBox, l, st, postalCode, c });
|
|
if (result.warning && result.dn) {
|
|
auditLog(req.user?.id, 'ad.create-user', 'ad_user', null, `AD user created with warning: ${username} - ${result.warning}`, req);
|
|
} else {
|
|
auditLog(req.user?.id, 'ad.create-user', 'ad_user', null, `Created AD user: ${username}`, req);
|
|
}
|
|
|
|
// Add user to groups if specified
|
|
let groupResults = [];
|
|
if (groups && Array.isArray(groups) && groups.length > 0 && result.dn) {
|
|
try {
|
|
groupResults = await addUserToGroups(result.dn, groups);
|
|
const addedCount = groupResults.filter(r => r.status === 'added').length;
|
|
auditLog(req.user?.id, 'ad.create-user', 'ad_user', null, `Added ${username} to ${addedCount} group(s)`, req);
|
|
} catch (groupErr) {
|
|
console.error('[WARN] Gruppenzuweisung fehlgeschlagen:', groupErr.message);
|
|
groupResults = groups.map(dn => ({ dn, status: 'error', error: groupErr.message }));
|
|
}
|
|
}
|
|
|
|
res.status(201).json({ ...result, groupResults });
|
|
} catch (err) {
|
|
auditLog(req.user?.id, 'ad.create-user-failed', 'ad_user', null, `Failed to create AD user: ${username} - ${err.message}`, req);
|
|
res.status(500).json({ error: 'Interner Serverfehler.' });
|
|
}
|
|
});
|
|
|
|
// Delete AD user (admin only)
|
|
router.delete('/delete-user', adminMiddleware, validate(deleteADUserSchema), async (req, res) => {
|
|
const { dn } = req.validatedBody;
|
|
try {
|
|
await deleteADUser(dn);
|
|
auditLog(req.user?.id, 'ad.delete-user', 'ad_user', null, `Deleted AD user: ${dn}`, req);
|
|
res.json({ success: true, message: 'Benutzer erfolgreich gelöscht.' });
|
|
} catch (err) {
|
|
res.status(500).json({ error: 'Fehler beim Löschen des AD-Benutzers: ' + err.message });
|
|
}
|
|
});
|
|
|
|
module.exports = router; |