mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-07-26 11:59:14 +00:00
Add ability to update manager for Active Directory users.
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/4557185a-6c8f-4519-939e-2acdaebd1657.jpg
This commit is contained in:
+406
-279
@@ -11,7 +11,6 @@ import {
|
||||
moveUserSchema,
|
||||
addToGroupSchema,
|
||||
removeFromGroupSchema,
|
||||
updateManagedBySchema,
|
||||
adUsers,
|
||||
adGroups,
|
||||
adOrgUnits,
|
||||
@@ -830,6 +829,105 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/ad-users/{id}/managed-by:
|
||||
* patch:
|
||||
* summary: Update the managedBy attribute for an AD user
|
||||
* tags: [AD Users]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* - name: id
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* managerDistinguishedName:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* description: The distinguished name of the manager, or null to remove the manager
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The updated AD user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/AdUser'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* description: User not found
|
||||
*/
|
||||
app.patch("/api/connections/:connectionId/ad-users/:id/managed-by", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const userId = parseInt(req.params.id);
|
||||
const { managerDistinguishedName } = req.body;
|
||||
|
||||
// Get the connection
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
// Get the user
|
||||
const user = await storage.getAdUser(userId);
|
||||
if (!user || user.connectionId !== connectionId) {
|
||||
return res.status(404).json({ message: "AD user not found" });
|
||||
}
|
||||
|
||||
// Connect to LDAP
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
console.error("LDAP connection error:", error);
|
||||
return res.status(500).json({ message: "Failed to connect to LDAP server", error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
// Set the managedBy attribute
|
||||
await ldapClient.setManagedBy(connectionId, user.distinguishedName, managerDistinguishedName);
|
||||
|
||||
// Update the user in the database
|
||||
const updatedUser = await storage.updateAdUser(userId, { managedBy: managerDistinguishedName });
|
||||
|
||||
// Log the action
|
||||
await storage.createAuditLogEntry({
|
||||
action: managerDistinguishedName ? "update_manager" : "remove_manager",
|
||||
targetId: user.objectGUID,
|
||||
details: {
|
||||
objectType: "user",
|
||||
managerDN: managerDistinguishedName,
|
||||
userDN: user.distinguishedName
|
||||
},
|
||||
userId: req.user?.id,
|
||||
connectionId
|
||||
});
|
||||
|
||||
return res.status(200).json(updatedUser);
|
||||
} catch (error) {
|
||||
console.error("Error updating managedBy attribute:", error);
|
||||
return res.status(500).json({ message: "Failed to update managedBy attribute", error: error.message });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
@@ -952,6 +1050,105 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/ad-groups/{id}/managed-by:
|
||||
* patch:
|
||||
* summary: Update the managedBy attribute for an AD group
|
||||
* tags: [AD Groups]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* - name: id
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* managerDistinguishedName:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* description: The distinguished name of the manager, or null to remove the manager
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The updated AD group
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/AdGroup'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* description: Group not found
|
||||
*/
|
||||
app.patch("/api/connections/:connectionId/ad-groups/:id/managed-by", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const groupId = parseInt(req.params.id);
|
||||
const { managerDistinguishedName } = req.body;
|
||||
|
||||
// Get the connection
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
// Get the group
|
||||
const group = await storage.getAdGroup(groupId);
|
||||
if (!group || group.connectionId !== connectionId) {
|
||||
return res.status(404).json({ message: "AD group not found" });
|
||||
}
|
||||
|
||||
// Connect to LDAP
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
console.error("LDAP connection error:", error);
|
||||
return res.status(500).json({ message: "Failed to connect to LDAP server", error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
// Set the managedBy attribute
|
||||
await ldapClient.setManagedBy(connectionId, group.distinguishedName, managerDistinguishedName);
|
||||
|
||||
// Update the group in the database
|
||||
const updatedGroup = await storage.updateAdGroup(groupId, { managedBy: managerDistinguishedName });
|
||||
|
||||
// Log the action
|
||||
await storage.createAuditLogEntry({
|
||||
action: managerDistinguishedName ? "update_manager" : "remove_manager",
|
||||
targetId: group.objectGUID,
|
||||
details: {
|
||||
objectType: "group",
|
||||
managerDN: managerDistinguishedName,
|
||||
groupDN: group.distinguishedName
|
||||
},
|
||||
userId: req.user?.id,
|
||||
connectionId
|
||||
});
|
||||
|
||||
return res.status(200).json(updatedGroup);
|
||||
} catch (error) {
|
||||
console.error("Error updating managedBy attribute:", error);
|
||||
return res.status(500).json({ message: "Failed to update managedBy attribute", error: error.message });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
@@ -1306,6 +1503,105 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/ad-org-units/{id}/managed-by:
|
||||
* patch:
|
||||
* summary: Update the managedBy attribute for an AD organizational unit
|
||||
* tags: [AD Organizational Units]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* - name: id
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* managerDistinguishedName:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* description: The distinguished name of the manager, or null to remove the manager
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The updated AD organizational unit
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/AdOrgUnit'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* description: Organizational unit not found
|
||||
*/
|
||||
app.patch("/api/connections/:connectionId/ad-org-units/:id/managed-by", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const ouId = parseInt(req.params.id);
|
||||
const { managerDistinguishedName } = req.body;
|
||||
|
||||
// Get the connection
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
// Get the OU
|
||||
const ou = await storage.getAdOrgUnit(ouId);
|
||||
if (!ou || ou.connectionId !== connectionId) {
|
||||
return res.status(404).json({ message: "AD organizational unit not found" });
|
||||
}
|
||||
|
||||
// Connect to LDAP
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
console.error("LDAP connection error:", error);
|
||||
return res.status(500).json({ message: "Failed to connect to LDAP server", error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
// Set the managedBy attribute
|
||||
await ldapClient.setManagedBy(connectionId, ou.distinguishedName, managerDistinguishedName);
|
||||
|
||||
// Update the OU in the database
|
||||
const updatedOU = await storage.updateAdOrgUnit(ouId, { managedBy: managerDistinguishedName });
|
||||
|
||||
// Log the action
|
||||
await storage.createAuditLogEntry({
|
||||
action: managerDistinguishedName ? "update_manager" : "remove_manager",
|
||||
targetId: ou.objectGUID,
|
||||
details: {
|
||||
objectType: "organizationalUnit",
|
||||
managerDN: managerDistinguishedName,
|
||||
ouDN: ou.distinguishedName
|
||||
},
|
||||
userId: req.user?.id,
|
||||
connectionId
|
||||
});
|
||||
|
||||
return res.status(200).json(updatedOU);
|
||||
} catch (error) {
|
||||
console.error("Error updating managedBy attribute:", error);
|
||||
return res.status(500).json({ message: "Failed to update managedBy attribute", error: error.message });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
@@ -1524,6 +1820,105 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/ad-computers/{id}/managed-by:
|
||||
* patch:
|
||||
* summary: Update the managedBy attribute for an AD computer
|
||||
* tags: [AD Computers]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* - name: id
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* managerDistinguishedName:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* description: The distinguished name of the manager, or null to remove the manager
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The updated AD computer
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/AdComputer'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* description: Computer not found
|
||||
*/
|
||||
app.patch("/api/connections/:connectionId/ad-computers/:id/managed-by", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const computerId = parseInt(req.params.id);
|
||||
const { managerDistinguishedName } = req.body;
|
||||
|
||||
// Get the connection
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
// Get the computer
|
||||
const computer = await storage.getAdComputer(computerId);
|
||||
if (!computer || computer.connectionId !== connectionId) {
|
||||
return res.status(404).json({ message: "AD computer not found" });
|
||||
}
|
||||
|
||||
// Connect to LDAP
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
console.error("LDAP connection error:", error);
|
||||
return res.status(500).json({ message: "Failed to connect to LDAP server", error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
// Set the managedBy attribute
|
||||
await ldapClient.setManagedBy(connectionId, computer.distinguishedName, managerDistinguishedName);
|
||||
|
||||
// Update the computer in the database
|
||||
const updatedComputer = await storage.updateAdComputer(computerId, { managedBy: managerDistinguishedName });
|
||||
|
||||
// Log the action
|
||||
await storage.createAuditLogEntry({
|
||||
action: managerDistinguishedName ? "update_manager" : "remove_manager",
|
||||
targetId: computer.objectGUID,
|
||||
details: {
|
||||
objectType: "computer",
|
||||
managerDN: managerDistinguishedName,
|
||||
computerDN: computer.distinguishedName
|
||||
},
|
||||
userId: req.user?.id,
|
||||
connectionId
|
||||
});
|
||||
|
||||
return res.status(200).json(updatedComputer);
|
||||
} catch (error) {
|
||||
console.error("Error updating managedBy attribute:", error);
|
||||
return res.status(500).json({ message: "Failed to update managedBy attribute", error: error.message });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
@@ -3297,285 +3692,17 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/managed-by:
|
||||
* get:
|
||||
* summary: Get the 'managedBy' attribute for an AD object
|
||||
* tags: [AD Objects]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* - name: objectGUID
|
||||
* in: query
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - name: objectType
|
||||
* in: query
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* enum: [user, group, computer, organizationalUnit]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The managedBy attribute
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* managedBy:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* description: Object not found
|
||||
*/
|
||||
app.get("/api/connections/:connectionId/managed-by", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
// This dedicated API endpoint has been replaced by object-specific endpoints using the PATCH method
|
||||
// See: /api/connections/:connectionId/ad-users/:id/managed-by,
|
||||
// /api/connections/:connectionId/ad-groups/:id/managed-by,
|
||||
// /api/connections/:connectionId/ad-computers/:id/managed-by,
|
||||
// /api/connections/:connectionId/ad-org-units/:id/managed-by
|
||||
|
||||
const objectGUID = req.query.objectGUID as string;
|
||||
const objectType = req.query.objectType as string;
|
||||
|
||||
if (!objectGUID || !objectType) {
|
||||
return res.status(400).json({ message: "objectGUID and objectType are required query parameters" });
|
||||
}
|
||||
|
||||
if (!['user', 'group', 'computer', 'organizationalUnit'].includes(objectType)) {
|
||||
return res.status(400).json({ message: "objectType must be one of: user, group, computer, organizationalUnit" });
|
||||
}
|
||||
|
||||
// Get the object distinguished name
|
||||
let objectDN;
|
||||
switch (objectType) {
|
||||
case 'user':
|
||||
const adUser = await storage.getAdUserByObjectGUID(connectionId, objectGUID);
|
||||
if (!adUser) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
objectDN = adUser.distinguishedName;
|
||||
break;
|
||||
case 'group':
|
||||
const adGroup = await storage.getAdGroupByObjectGUID(connectionId, objectGUID);
|
||||
if (!adGroup) {
|
||||
return res.status(404).json({ message: "Group not found" });
|
||||
}
|
||||
objectDN = adGroup.distinguishedName;
|
||||
break;
|
||||
case 'computer':
|
||||
const adComputer = await storage.getAdComputerByObjectGUID(connectionId, objectGUID);
|
||||
if (!adComputer) {
|
||||
return res.status(404).json({ message: "Computer not found" });
|
||||
}
|
||||
objectDN = adComputer.distinguishedName;
|
||||
break;
|
||||
case 'organizationalUnit':
|
||||
const adOU = await storage.getAdOrgUnitByObjectGUID(connectionId, objectGUID);
|
||||
if (!adOU) {
|
||||
return res.status(404).json({ message: "Organizational Unit not found" });
|
||||
}
|
||||
objectDN = adOU.distinguishedName;
|
||||
break;
|
||||
}
|
||||
|
||||
// Connect to LDAP
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
console.error("LDAP connection error:", error);
|
||||
return res.status(500).json({ message: "Failed to connect to LDAP server", error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the managedBy attribute
|
||||
const managedBy = await ldapClient.getManagedBy(connectionId, objectDN);
|
||||
|
||||
return res.status(200).json({ managedBy });
|
||||
} catch (error) {
|
||||
console.error("Error getting managedBy attribute:", error);
|
||||
return res.status(500).json({ message: "Failed to get managedBy attribute", error: error.message });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/managed-by:
|
||||
* post:
|
||||
* summary: Set the 'managedBy' attribute for an AD object
|
||||
* tags: [AD Objects]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - objectGUID
|
||||
* - objectType
|
||||
* properties:
|
||||
* objectGUID:
|
||||
* type: string
|
||||
* managerDistinguishedName:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* objectType:
|
||||
* type: string
|
||||
* enum: [user, group, computer, organizationalUnit]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: ManagedBy attribute updated successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* message:
|
||||
* type: string
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* description: Object not found
|
||||
*/
|
||||
app.post("/api/connections/:connectionId/managed-by", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
// Parse and validate request body
|
||||
try {
|
||||
updateManagedBySchema.parse(req.body);
|
||||
} catch (err) {
|
||||
if (err instanceof ZodError) {
|
||||
return handleZodError(err, res);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
const { objectGUID, managerDistinguishedName, objectType } = req.body;
|
||||
|
||||
// Get the object distinguished name
|
||||
let objectDN;
|
||||
let objectName;
|
||||
switch (objectType) {
|
||||
case 'user':
|
||||
const adUser = await storage.getAdUserByObjectGUID(connectionId, objectGUID);
|
||||
if (!adUser) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
objectDN = adUser.distinguishedName;
|
||||
objectName = adUser.displayName || adUser.sAMAccountName;
|
||||
break;
|
||||
case 'group':
|
||||
const adGroup = await storage.getAdGroupByObjectGUID(connectionId, objectGUID);
|
||||
if (!adGroup) {
|
||||
return res.status(404).json({ message: "Group not found" });
|
||||
}
|
||||
objectDN = adGroup.distinguishedName;
|
||||
objectName = adGroup.sAMAccountName;
|
||||
break;
|
||||
case 'computer':
|
||||
const adComputer = await storage.getAdComputerByObjectGUID(connectionId, objectGUID);
|
||||
if (!adComputer) {
|
||||
return res.status(404).json({ message: "Computer not found" });
|
||||
}
|
||||
objectDN = adComputer.distinguishedName;
|
||||
objectName = adComputer.name;
|
||||
break;
|
||||
case 'organizationalUnit':
|
||||
const adOU = await storage.getAdOrgUnitByObjectGUID(connectionId, objectGUID);
|
||||
if (!adOU) {
|
||||
return res.status(404).json({ message: "Organizational Unit not found" });
|
||||
}
|
||||
objectDN = adOU.distinguishedName;
|
||||
objectName = adOU.name;
|
||||
break;
|
||||
}
|
||||
|
||||
// Connect to LDAP
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
console.error("LDAP connection error:", error);
|
||||
return res.status(500).json({ message: "Failed to connect to LDAP server", error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
// Set the managedBy attribute
|
||||
await ldapClient.setManagedBy(connectionId, objectDN, managerDistinguishedName);
|
||||
|
||||
// Update the database record
|
||||
const updateData = { managedBy: managerDistinguishedName };
|
||||
switch (objectType) {
|
||||
case 'user':
|
||||
await storage.updateAdUserByObjectGUID(connectionId, objectGUID, updateData);
|
||||
break;
|
||||
case 'group':
|
||||
await storage.updateAdGroupByObjectGUID(connectionId, objectGUID, updateData);
|
||||
break;
|
||||
case 'computer':
|
||||
await storage.updateAdComputerByObjectGUID(connectionId, objectGUID, updateData);
|
||||
break;
|
||||
case 'organizationalUnit':
|
||||
await storage.updateAdOrgUnitByObjectGUID(connectionId, objectGUID, updateData);
|
||||
break;
|
||||
}
|
||||
|
||||
// Log the action
|
||||
await storage.createAuditLogEntry({
|
||||
action: `update_managed_by:${objectType}`,
|
||||
targetId: objectGUID,
|
||||
details: {
|
||||
objectDN,
|
||||
managerDN: managerDistinguishedName
|
||||
},
|
||||
userId: req.user?.id,
|
||||
connectionId
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
message: `ManagedBy attribute successfully updated for ${objectName}`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error updating managedBy attribute:", error);
|
||||
return res.status(500).json({ message: "Failed to update managedBy attribute", error: error.message });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// This dedicated API endpoint has been replaced by object-specific endpoints using the PATCH method
|
||||
// See: /api/connections/:connectionId/ad-users/:objectGuid,
|
||||
// /api/connections/:connectionId/ad-groups/:objectGuid,
|
||||
// /api/connections/:connectionId/ad-computers/:objectGuid,
|
||||
// /api/connections/:connectionId/ad-org-units/:objectGuid
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
|
||||
+4
-2
@@ -982,7 +982,7 @@ export class DatabaseStorage implements IStorage {
|
||||
debug(`Getting audit logs: connectionId=${connectionId}, userId=${userId}, page=${page}, pageSize=${pageSize}`);
|
||||
|
||||
// Define the base query for counting total records
|
||||
let countQuery = db.select({ count: sql`count(*)` }).from(auditLogs);
|
||||
let countQuery = db.select({ count: sql`count(*)::int` }).from(auditLogs);
|
||||
let dataQuery = db.select().from(auditLogs);
|
||||
|
||||
// Apply filters if provided
|
||||
@@ -1005,7 +1005,9 @@ export class DatabaseStorage implements IStorage {
|
||||
|
||||
// Get total count of records
|
||||
const countResult = await countQuery;
|
||||
const totalRecords = parseInt(countResult[0].count.toString());
|
||||
const totalRecords = typeof countResult[0].count === 'number'
|
||||
? countResult[0].count
|
||||
: parseInt(String(countResult[0].count), 10);
|
||||
|
||||
// Calculate pagination values
|
||||
const totalPages = Math.ceil(totalRecords / pageSize);
|
||||
|
||||
+2
-7
@@ -311,12 +311,7 @@ export const removeFromGroupSchema = z.object({
|
||||
objectType: z.enum(["user", "computer"]),
|
||||
});
|
||||
|
||||
// ManagedBy operation schema
|
||||
export const updateManagedBySchema = z.object({
|
||||
objectGUID: z.string().min(1, "Object GUID is required"),
|
||||
managerDistinguishedName: z.string().nullable(),
|
||||
objectType: z.enum(["user", "group", "computer", "organizationalUnit"]),
|
||||
});
|
||||
// ManagedBy operation schema is no longer needed as it's been replaced by object-specific PATCH endpoints
|
||||
|
||||
// Export types
|
||||
export type Role = typeof roles.$inferSelect;
|
||||
@@ -350,7 +345,7 @@ export type MoveComputer = z.infer<typeof moveComputerSchema>;
|
||||
export type MoveUser = z.infer<typeof moveUserSchema>;
|
||||
export type AddToGroup = z.infer<typeof addToGroupSchema>;
|
||||
export type RemoveFromGroup = z.infer<typeof removeFromGroupSchema>;
|
||||
export type UpdateManagedBy = z.infer<typeof updateManagedBySchema>;
|
||||
|
||||
|
||||
// LDAP Query Builder schemas
|
||||
export const ldapFilterObjectClasses = ["user", "group", "organizationalUnit", "computer", "domain"] as const;
|
||||
|
||||
Reference in New Issue
Block a user