Skip to content

Commit f088c34

Browse files
committed
Moved to batch requests for app proxies
1 parent 66524f9 commit f088c34

File tree

1 file changed

+83
-50
lines changed

1 file changed

+83
-50
lines changed

entra/libexec/agent_ms_entra

Lines changed: 83 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -266,11 +266,11 @@ def get_appid_via_batch(
266266
apps_batch_dict = apps_batch_response.json()
267267
apps_batch = apps_batch_dict.get("responses", [])
268268

269-
for batch_response in apps_batch:
270-
status = batch_response["status"]
269+
for batch_app in apps_batch:
270+
status = batch_app["status"]
271271

272272
if status == 200:
273-
all_object_ids.append(batch_response["body"].get("id"))
273+
all_object_ids.append(batch_app["body"].get("id"))
274274
elif status == 429:
275275
error = Exception(f"Error {status}: Throttling error.")
276276
handle_error(
@@ -279,7 +279,7 @@ def get_appid_via_batch(
279279
24,
280280
)
281281
else:
282-
error_body = batch_response.get("body", {}).get("error", {}).get("message", "")
282+
error_body = batch_app.get("body", {}).get("error", {}).get("message", "")
283283
error = Exception(f"Error {status}: {error_body}")
284284
handle_error(error, "Failed to get Entra app proxy object IDs.", 25)
285285

@@ -301,6 +301,80 @@ def get_entra_app_proxy_object_ids(
301301
return get_appid_via_batch(app_ids, headers, timeout, proxy)
302302

303303

304+
def get_app_proxy_certs_via_batch(
305+
app_object_ids: list[str], headers: dict, timeout: float, proxy: HTTPProxyConfig
306+
) -> list[dict]:
307+
app_proxies = []
308+
309+
for i in range(0, len(app_object_ids), GRAPH_API_BATCH_SIZE):
310+
batch_app_ids = app_object_ids[i : i + GRAPH_API_BATCH_SIZE]
311+
312+
apps_batch_requests = {
313+
"requests": [
314+
{
315+
"id": str(idx),
316+
"method": "GET",
317+
"url": (
318+
f"/applications/{app_id}?$select=appId,id,displayName,notes,"
319+
"onPremisesPublishing"
320+
),
321+
}
322+
for idx, app_id in enumerate(batch_app_ids)
323+
]
324+
}
325+
try:
326+
# onPremisesPublishing is not available in v1.0 (2025-02-09)
327+
apps_batch_response = requests.post(
328+
f"{GRAPH_API_BETA}/$batch",
329+
headers={**headers, "Content-Type": "application/json"},
330+
json=apps_batch_requests,
331+
timeout=timeout,
332+
proxies=proxy.to_requests_proxies(),
333+
)
334+
apps_batch_response.raise_for_status()
335+
except requests.exceptions.Timeout as err:
336+
handle_error(err, "Timeout while getting Entra app proxy apps.", 14)
337+
except requests.exceptions.RequestException as err:
338+
error_message = "Failed to get Entra app proxy apps."
339+
error_message_details = {
340+
429: f"{error_message} Request has been throttled.",
341+
}
342+
status_code = getattr(err.response, "status_code", 0)
343+
handle_error(err, error_message_details.get(status_code, error_message), 26)
344+
345+
apps_batch_dict = apps_batch_response.json()
346+
apps_batch = apps_batch_dict.get("responses", [])
347+
348+
for batch_app in apps_batch:
349+
status = batch_app["status"]
350+
351+
if status == 200:
352+
app_body = batch_app["body"]
353+
app_on_prem = app_body.get("onPremisesPublishing", {})
354+
355+
if not app_on_prem.get("isOnPremPublishingEnabled"):
356+
continue
357+
358+
cert_metadata = app_on_prem.get("verifiedCustomDomainCertificatesMetadata", {})
359+
if not cert_metadata:
360+
continue
361+
362+
app_proxies.append(app_body)
363+
elif status == 429:
364+
error = Exception(f"Error {status}: Throttling error.")
365+
handle_error(
366+
error,
367+
"Failed to get Entra app proxies. Request has been throttled.",
368+
27,
369+
)
370+
else:
371+
error_body = batch_app.get("body", {}).get("error", {}).get("message", "")
372+
error = Exception(f"Error {status}: {error_body}")
373+
handle_error(error, "Failed to get Entra app proxies.", 28)
374+
375+
return app_proxies
376+
377+
304378
class AppProxyInfo(TypedDict):
305379
app_appid: str
306380
app_id: str
@@ -323,50 +397,9 @@ def get_entra_app_proxy_certs(
323397

324398
app_object_ids = get_entra_app_proxy_object_ids(token, timeout, proxy, app_app_ids)
325399

326-
# onPremisesPublishing is not available in v1.0 (2025-02-09)
327-
base_url = f"{GRAPH_API_BETA}/applications"
328-
attributes = "appId,id,displayName,notes,onPremisesPublishing"
329-
330400
headers = {"Authorization": f"Bearer {token}"}
331401

332-
entra_app_proxy_apps = []
333-
334-
for app_id in app_object_ids:
335-
entra_app_proxy_url = f"{base_url}/{app_id}?$select={attributes}"
336-
337-
try:
338-
entra_app_proxy_app_response = requests.get(
339-
entra_app_proxy_url,
340-
headers=headers,
341-
timeout=timeout,
342-
proxies=proxy.to_requests_proxies(),
343-
)
344-
entra_app_proxy_app_response.raise_for_status()
345-
except requests.exceptions.Timeout as err:
346-
handle_error(err, "Timeout while getting Entra app proxy certificate.", 14)
347-
except requests.exceptions.RequestException as err:
348-
error_message = "Failed to get Entra app proxy certificate."
349-
error_message_details = {
350-
403: (
351-
f"{error_message} Please check application API permissions. At least "
352-
"Directory.Read.All is required."
353-
),
354-
429: f"{error_message} Request has been throttled.",
355-
}
356-
status_code = getattr(err.response, "status_code", 0)
357-
handle_error(err, error_message_details.get(status_code, error_message), 26)
358-
359-
entra_app_proxy_app_dict = entra_app_proxy_app_response.json()
360-
361-
app_on_prem = entra_app_proxy_app_dict.get("onPremisesPublishing", {})
362-
if not app_on_prem.get("isOnPremPublishingEnabled"):
363-
continue
364-
365-
cert_metadata = app_on_prem.get("verifiedCustomDomainCertificatesMetadata", {})
366-
if not cert_metadata:
367-
continue
368-
369-
entra_app_proxy_apps.append(entra_app_proxy_app_dict)
402+
entra_app_proxy_apps = get_app_proxy_certs_via_batch(app_object_ids, headers, timeout, proxy)
370403

371404
app_info_list: list[AppProxyInfo] = [
372405
AppProxyInfo(
@@ -426,7 +459,7 @@ def get_entra_app_registration_creds(
426459
)
427460
entra_app_registration_response.raise_for_status()
428461
except requests.exceptions.Timeout as err:
429-
handle_error(err, "Timeout while getting Entra app registrations.", 15)
462+
handle_error(err, "Timeout while getting Entra app registrations.", 16)
430463
except requests.exceptions.RequestException as err:
431464
error_message = "Failed to get Entra app registrations."
432465
error_message_details = {
@@ -524,7 +557,7 @@ def get_entra_ca_vpn_certs(token: str, timeout: float, proxy: HTTPProxyConfig) -
524557
)
525558
entra_ca_vpn_certs_response.raise_for_status()
526559
except requests.exceptions.Timeout as err:
527-
handle_error(err, "Timeout while getting Entra Conditional Access VPN certificate.", 16)
560+
handle_error(err, "Timeout while getting Entra Conditional Access VPN certificate.", 17)
528561
except requests.exceptions.RequestException as err:
529562
error_message = "Failed to get Entra Conditional Access VPN certificate."
530563
error_message_details = {
@@ -595,7 +628,7 @@ def get_entra_sync(
595628
)
596629
entra_sync_response.raise_for_status()
597630
except requests.exceptions.Timeout as err:
598-
handle_error(err, "Timeout while getting Entra Connect/Cloud Sync.", 17)
631+
handle_error(err, "Timeout while getting Entra Connect/Cloud Sync.", 18)
599632
except requests.exceptions.RequestException as err:
600633
error_message = "Failed to get Entra Connect/Cloud Sync."
601634
error_message_details = {
@@ -651,7 +684,7 @@ def get_entra_saml_certs(token: str, timeout: float, proxy: HTTPProxyConfig) ->
651684
entra_saml_certs_response.raise_for_status()
652685
except requests.exceptions.Timeout as err:
653686
handle_error(
654-
err, "Timeout while getting Entra service principals with SAML configured.", 18
687+
err, "Timeout while getting Entra service principals with SAML configured.", 19
655688
)
656689
except requests.exceptions.RequestException as err:
657690
error_message = "Failed to get Entra service principals with SAML configured."

0 commit comments

Comments
 (0)