main
py 289 lines 11.7 KB
Raw
1 from fastapi import HTTPException
2 from loguru import logger
3
4 from app.connectors.wazuh_manager.schema.groups import (
5 WazuhGroupConfigurationUpdateResponse,
6 )
7 from app.connectors.wazuh_manager.schema.groups import WazuhGroupFileResponse
8 from app.connectors.wazuh_manager.schema.groups import WazuhGroupFilesResponse
9 from app.connectors.wazuh_manager.schema.groups import WazuhGroupsResponse
10 from app.connectors.wazuh_manager.utils.universal import send_get_request
11 from app.connectors.wazuh_manager.utils.universal import send_put_request
12
13
14 async def get_wazuh_groups(**params) -> WazuhGroupsResponse:
15 """
16 Fetch Wazuh groups from the Wazuh Manager API.
17
18 Args:
19 **params: All query parameters passed directly to the API
20
21 Returns:
22 WazuhGroupsResponse: Structured response with groups data
23
24 Raises:
25 HTTPException: If there's an error fetching the groups
26 """
27 # Filter out None values
28 clean_params = {k: v for k, v in params.items() if v is not None}
29
30 # Handle list parameters that need to be joined as comma-separated strings
31 if "groups_list" in clean_params and isinstance(clean_params["groups_list"], list):
32 clean_params["groups_list"] = ",".join(clean_params["groups_list"])
33 if "select" in clean_params and isinstance(clean_params["select"], list):
34 clean_params["select"] = ",".join(clean_params["select"])
35
36 logger.debug(f"Requesting Wazuh groups with params: {clean_params}")
37
38 try:
39 response = await send_get_request(endpoint="/groups", params=clean_params)
40
41 # Check if the API request was successful
42 if not response.get("success"):
43 error_detail = response.get("message", "Failed to fetch groups from Wazuh API")
44 logger.error(f"Wazuh API error: {error_detail}")
45 raise HTTPException(status_code=500, detail=error_detail)
46
47 # Extract data from nested response structure
48 wazuh_data = response.get("data", {}).get("data", {})
49 groups = wazuh_data.get("affected_items", [])
50 total_items = wazuh_data.get("total_affected_items", len(groups))
51
52 logger.info(f"Retrieved {len(groups)} of {total_items} Wazuh groups")
53
54 return WazuhGroupsResponse(
55 success=True,
56 message=f"Successfully retrieved {len(groups)} groups",
57 results=groups,
58 total_items=total_items,
59 )
60
61 except HTTPException:
62 # Re-raise HTTP exceptions as-is
63 raise
64 except Exception as e:
65 logger.error(f"Error fetching Wazuh groups: {e}")
66 raise HTTPException(status_code=500, detail=f"Error fetching groups: {str(e)}")
67
68
69 async def get_wazuh_group_file(group_id: str, filename: str, **params) -> WazuhGroupFileResponse:
70 """
71 Fetch the content of a specific file from a Wazuh group.
72
73 Args:
74 group_id: The ID (name) of the group
75 filename: The name of the file to fetch (e.g., "agent.conf")
76 **params: All query parameters passed directly to the API
77
78 Returns:
79 WazuhGroupFileResponse: Structured response with group file content
80
81 Raises:
82 HTTPException: If there's an error fetching the group file
83 """
84 # Filter out None values
85 clean_params = {k: v for k, v in params.items() if v is not None}
86
87 # Handle list parameters that need to be joined as comma-separated strings
88 if "type" in clean_params and isinstance(clean_params["type"], list):
89 clean_params["type"] = ",".join(clean_params["type"])
90
91 # Check if raw content is requested
92 is_raw = clean_params.get("raw", False)
93
94 logger.debug(f"Requesting Wazuh group file '{filename}' for group '{group_id}' with params: {clean_params}")
95
96 try:
97 response = await send_get_request(endpoint=f"/groups/{group_id}/files/{filename}", params=clean_params)
98 logger.info(f"Response: {response}")
99
100 # Check if the API request was successful
101 if not response.get("success"):
102 error_detail = response.get("message", f"Failed to fetch group file '{filename}' for group '{group_id}'")
103 logger.error(f"Wazuh API error: {error_detail}")
104
105 # Handle specific errors
106 if "not found" in error_detail.lower():
107 raise HTTPException(status_code=404, detail=f"Group file '{filename}' not found in group '{group_id}'")
108 else:
109 raise HTTPException(status_code=500, detail=error_detail)
110
111 # Handle raw response differently
112 if is_raw:
113 # For raw responses, the content is in response["data"]
114 content = response.get("data", "")
115 logger.info(f"Retrieved raw content for group file '{filename}' in group '{group_id}' ({len(content)} characters)")
116
117 return WazuhGroupFileResponse(
118 success=True,
119 message=f"Successfully retrieved raw content for group file '{filename}' in group '{group_id}'",
120 group_id=group_id,
121 filename=filename,
122 content=content,
123 is_raw=True,
124 total_items=None,
125 )
126
127 # Handle structured response (non-raw)
128 wazuh_data = response.get("data", {}).get("data", {})
129 affected_items = wazuh_data.get("affected_items", [])
130 total_items = wazuh_data.get("total_affected_items", len(affected_items))
131
132 if not affected_items:
133 raise HTTPException(status_code=404, detail=f"No content found for group file '{filename}' in group '{group_id}'")
134
135 # Extract the content from the first affected item
136 content = affected_items[0] if affected_items else {}
137
138 logger.info(f"Retrieved structured content for group file '{filename}' in group '{group_id}' with {total_items} affected items")
139
140 return WazuhGroupFileResponse(
141 success=True,
142 message=f"Successfully retrieved content for group file '{filename}' in group '{group_id}'",
143 group_id=group_id,
144 filename=filename,
145 content=content,
146 is_raw=False,
147 total_items=total_items,
148 )
149
150 except HTTPException:
151 # Re-raise HTTP exceptions as-is
152 raise
153 except Exception as e:
154 logger.error(f"Error fetching Wazuh group file '{filename}' for group '{group_id}': {e}")
155 raise HTTPException(status_code=500, detail=f"Error fetching group file: {str(e)}")
156
157
158 async def get_wazuh_group_files(group_id: str, **params) -> WazuhGroupFilesResponse:
159 """
160 Fetch the list of files in a Wazuh group.
161
162 Args:
163 group_id: The ID (name) of the group
164 **params: All query parameters passed directly to the API
165
166 Returns:
167 WazuhGroupFilesResponse: Structured response with group files data
168
169 Raises:
170 HTTPException: If there's an error fetching the group files
171 """
172 # Filter out None values
173 clean_params = {k: v for k, v in params.items() if v is not None}
174
175 # Handle list parameters that need to be joined as comma-separated strings
176 if "select" in clean_params and isinstance(clean_params["select"], list):
177 clean_params["select"] = ",".join(clean_params["select"])
178
179 logger.debug(f"Requesting Wazuh group files for group '{group_id}' with params: {clean_params}")
180
181 try:
182 response = await send_get_request(endpoint=f"/groups/{group_id}/files", params=clean_params)
183
184 # Check if the API request was successful
185 if not response.get("success"):
186 error_detail = response.get("message", f"Failed to fetch group files for group '{group_id}'")
187 logger.error(f"Wazuh API error: {error_detail}")
188
189 # Handle specific errors
190 if "not found" in error_detail.lower():
191 raise HTTPException(status_code=404, detail=f"Group '{group_id}' not found")
192 else:
193 raise HTTPException(status_code=500, detail=error_detail)
194
195 # Extract data from nested response structure
196 wazuh_data = response.get("data", {}).get("data", {})
197 files = wazuh_data.get("affected_items", [])
198 total_items = wazuh_data.get("total_affected_items", len(files))
199
200 logger.info(f"Retrieved {len(files)} of {total_items} Wazuh group files for group '{group_id}'")
201
202 return WazuhGroupFilesResponse(
203 success=True,
204 message=f"Successfully retrieved {len(files)} files for group '{group_id}'",
205 group_id=group_id,
206 results=files,
207 total_items=total_items,
208 )
209
210 except HTTPException:
211 # Re-raise HTTP exceptions as-is
212 raise
213 except Exception as e:
214 logger.error(f"Error fetching Wazuh group files for group '{group_id}': {e}")
215 raise HTTPException(status_code=500, detail=f"Error fetching group files: {str(e)}")
216
217
218 async def update_wazuh_group_configuration(group_id: str, configuration: str, **params) -> WazuhGroupConfigurationUpdateResponse:
219 """
220 Update a Wazuh group's configuration.
221
222 Args:
223 group_id: The ID (name) of the group
224 configuration: The XML configuration content to update
225 **params: All query parameters passed directly to the API
226
227 Returns:
228 WazuhGroupConfigurationUpdateResponse: Structured response with update result
229
230 Raises:
231 HTTPException: If there's an error updating the group configuration
232 """
233 # Filter out None values
234 clean_params = {k: v for k, v in params.items() if v is not None}
235
236 logger.debug(f"Updating Wazuh group configuration for group '{group_id}' with params: {clean_params}")
237 logger.debug(f"Configuration content length: {len(configuration)} characters")
238
239 try:
240 # Validate that we have configuration content
241 if not configuration or not configuration.strip():
242 raise HTTPException(status_code=400, detail="Configuration content cannot be empty")
243
244 # Basic XML validation (check for XML tags)
245 if not configuration.strip().startswith("<"):
246 logger.warning("Configuration does not appear to be XML format")
247 raise HTTPException(status_code=400, detail="Configuration must be valid XML format")
248
249 # Send PUT request with XML data
250 response = await send_put_request(
251 endpoint=f"/groups/{group_id}/configuration",
252 data=configuration,
253 params=clean_params,
254 xml_data=True,
255 )
256
257 # Check if the API request was successful
258 if not response.get("success"):
259 error_detail = response.get("message", f"Failed to update group configuration for group '{group_id}'")
260 status_code = response.get("status_code", 500)
261 logger.error(f"Wazuh API error: {error_detail}")
262
263 # Handle specific errors
264 if "not found" in error_detail.lower():
265 raise HTTPException(status_code=404, detail=f"Group '{group_id}' not found")
266 elif status_code == 400:
267 raise HTTPException(status_code=400, detail=f"Invalid configuration data: {error_detail}")
268 else:
269 raise HTTPException(status_code=status_code, detail=error_detail)
270
271 # Extract data from response
272 wazuh_data = response.get("data", {}).get("data", {})
273 total_items = wazuh_data.get("total_affected_items", 1)
274
275 logger.info(f"Successfully updated configuration for group '{group_id}'")
276
277 return WazuhGroupConfigurationUpdateResponse(
278 success=True,
279 message=f"Successfully updated configuration for group '{group_id}'",
280 group_id=group_id,
281 total_items=total_items,
282 )
283
284 except HTTPException:
285 # Re-raise HTTP exceptions as-is
286 raise
287 except Exception as e:
288 logger.error(f"Error updating Wazuh group configuration for group '{group_id}': {e}")
289 raise HTTPException(status_code=500, detail=f"Error updating group configuration: {str(e)}")