@@ -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+
304378class 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