@@ -32,12 +32,14 @@ def get_frontend_token(cmd):
3232
3333 # Priority 0: explicit token via environment variable (for local/test envs
3434 # only)
35- env_token = os .environ .get (' MANAGEDCLEANROOM_ACCESS_TOKEN' )
35+ env_token = os .environ .get (" MANAGEDCLEANROOM_ACCESS_TOKEN" )
3636 if env_token :
3737 logger .warning (
38- "Using token from MANAGEDCLEANROOM_ACCESS_TOKEN env var FOR TESTING PURPOSES ONLY" )
38+ "Using token from MANAGEDCLEANROOM_ACCESS_TOKEN env var FOR TESTING PURPOSES ONLY"
39+ )
3940 from collections import namedtuple
40- AccessToken = namedtuple ('AccessToken' , ['token' , 'expires_on' ])
41+
42+ AccessToken = namedtuple ("AccessToken" , ["token" , "expires_on" ])
4143 token_obj = AccessToken (token = env_token , expires_on = 0 )
4244 return (token_obj , subscription , None )
4345
@@ -49,20 +51,46 @@ def get_frontend_token(cmd):
4951 msal_token = get_msal_token (cmd )
5052 if msal_token :
5153 logger .debug ("Using MSAL device code flow token" )
52- return (msal_token [0 ], subscription , msal_token [2 ])
54+ from collections import namedtuple
55+
56+ AccessToken = namedtuple ("AccessToken" , ["token" , "expires_on" ])
57+ token_obj = AccessToken (token = msal_token [0 ], expires_on = 0 )
58+ return (token_obj , subscription , msal_token [2 ])
5359
5460 logger .debug ("Using Azure CLI (az login) token" )
55- return profile .get_raw_token (
56- subscription = subscription ,
57- resource = auth_scope
61+ raw_token = profile .get_raw_token (
62+ subscription = subscription , resource = auth_scope
5863 )
5964
65+ # Normalize to AccessToken object
66+ from collections import namedtuple
67+
68+ AccessToken = namedtuple ("AccessToken" , ["token" , "expires_on" ])
69+
70+ # Handle different return types from get_raw_token
71+ if isinstance (raw_token , tuple ) and len (raw_token ) >= 3 :
72+ # Tuple format: ('Bearer', 'token_string', {...})
73+ # raw_token[2] should be a dict with metadata
74+ metadata = raw_token [2 ] if isinstance (raw_token [2 ], dict ) else {}
75+ token_obj = AccessToken (
76+ token = raw_token [1 ], expires_on = metadata .get ("expiresOn" , 0 )
77+ )
78+ elif hasattr (raw_token , "token" ):
79+ # Already AccessToken object
80+ token_obj = raw_token
81+ else :
82+ # Raw string token
83+ token_obj = AccessToken (token = str (raw_token ), expires_on = 0 )
84+
85+ return (token_obj , subscription , None )
86+
6087 except Exception as ex :
6188 raise CLIError (
62- f'Failed to get access token: { str (ex )} \n \n '
63- 'Please authenticate using one of:\n '
64- ' 1. az managedcleanroom frontend login (MSAL device code flow)\n '
65- ' 2. az login (Azure CLI authentication)\n ' )
89+ f"Failed to get access token: { str (ex )} \n \n "
90+ "Please authenticate using one of:\n "
91+ " 1. az managedcleanroom frontend login (MSAL device code flow)\n "
92+ " 2. az login (Azure CLI authentication)\n "
93+ ) from ex
6694
6795
6896def get_frontend_config (cmd ):
@@ -73,7 +101,7 @@ def get_frontend_config(cmd):
73101 :rtype: str or None
74102 """
75103 config = cmd .cli_ctx .config
76- return config .get (' managedcleanroom-frontend' , ' endpoint' , fallback = None )
104+ return config .get (" managedcleanroom-frontend" , " endpoint" , fallback = None )
77105
78106
79107def set_frontend_config (cmd , endpoint ):
@@ -83,10 +111,7 @@ def set_frontend_config(cmd, endpoint):
83111 :param endpoint: API endpoint URL to store
84112 :type endpoint: str
85113 """
86- cmd .cli_ctx .config .set_value (
87- 'managedcleanroom-frontend' ,
88- 'endpoint' ,
89- endpoint )
114+ cmd .cli_ctx .config .set_value ("managedcleanroom-frontend" , "endpoint" , endpoint )
90115
91116
92117def get_frontend_client (cmd , endpoint = None , api_version = None ):
@@ -104,33 +129,40 @@ def get_frontend_client(cmd, endpoint=None, api_version=None):
104129 :raises: CLIError if token fetch fails or endpoint not configured
105130 """
106131 from .analytics_frontend_api import AnalyticsFrontendAPI
107- from azure .core .pipeline .policies import BearerTokenCredentialPolicy , SansIOHTTPPolicy
132+ from azure .core .pipeline .policies import (
133+ BearerTokenCredentialPolicy ,
134+ SansIOHTTPPolicy ,
135+ )
108136
109137 # Use provided api_version or default
110138 if api_version is None :
111- api_version = ' 2026-03-01-preview'
139+ api_version = " 2026-03-01-preview"
112140
113141 api_endpoint = endpoint or get_frontend_config (cmd )
114142 if not api_endpoint :
115143 raise CLIError (
116- 'Analytics Frontend API endpoint not configured.\n '
117- 'Configure using: az config set managedcleanroom-frontend.endpoint=<url>\n '
118- 'Or use the --endpoint flag with your command.' )
144+ "Analytics Frontend API endpoint not configured.\n "
145+ "Configure using: az config set managedcleanroom-frontend.endpoint=<url>\n "
146+ "Or use the --endpoint flag with your command."
147+ )
119148
120149 access_token_obj , _ , _ = get_frontend_token (cmd )
121150
122151 logger .debug (
123- "Creating Analytics Frontend API client for endpoint: %s" ,
124- api_endpoint )
152+ "Creating Analytics Frontend API client for endpoint: %s" , api_endpoint
153+ )
125154
126155 # Check if this is a local development endpoint
127- is_local = api_endpoint .startswith (
128- 'http://localhost' ) or api_endpoint .startswith ('http://127.0.0.1' )
156+ is_local = api_endpoint .startswith ("http://localhost" ) or api_endpoint .startswith (
157+ "http://127.0.0.1"
158+ )
129159
130160 # Create simple credential wrapper for the access token
131- credential = type ('TokenCredential' , (), {
132- 'get_token' : lambda self , * args , ** kwargs : access_token_obj
133- })()
161+ credential = type (
162+ "TokenCredential" ,
163+ (),
164+ {"get_token" : lambda self , * args , ** kwargs : access_token_obj },
165+ )()
134166
135167 if is_local :
136168 # For local development, create a custom auth policy that bypasses
@@ -146,7 +178,7 @@ def on_request(self, request):
146178 # Extract token string from AccessToken object
147179 # The token might be a tuple ('Bearer', 'token_string') or just
148180 # the token string
149- if hasattr (self ._token , ' token' ):
181+ if hasattr (self ._token , " token" ):
150182 token_value = self ._token .token
151183 else :
152184 token_value = self ._token
@@ -157,29 +189,43 @@ def on_request(self, request):
157189 else :
158190 token_string = str (token_value )
159191
160- auth_header = f' Bearer { token_string } '
192+ auth_header = f" Bearer { token_string } "
161193 logger .debug (
162- "Setting Authorization header: Bearer %s..." , token_string [:50 ])
163- request .http_request .headers ['Authorization' ] = auth_header
194+ "Setting Authorization header: Bearer %s..." , token_string [:50 ]
195+ )
196+ request .http_request .headers ["Authorization" ] = auth_header
164197
165198 auth_policy = LocalBearerTokenPolicy (access_token_obj )
166199 else :
167200 # For production, use standard bearer token policy with HTTPS
168201 # enforcement
169202 # Use configured auth_scope with .default suffix for Azure SDK
170203 from ._msal_auth import get_auth_scope
204+
171205 scope = get_auth_scope (cmd )
172- if not scope .endswith (' /.default' ):
173- scope = f' { scope } /.default'
206+ if not scope .endswith (" /.default" ):
207+ scope = f" { scope } /.default"
174208
175- auth_policy = BearerTokenCredentialPolicy (
176- credential ,
177- scope
209+ auth_policy = BearerTokenCredentialPolicy (credential , scope )
210+
211+ # Handle SSL verification settings
212+ import os
213+
214+ client_kwargs = {}
215+ if os .environ .get ("AZURE_CLI_DISABLE_CONNECTION_VERIFICATION" ):
216+ logger .warning (
217+ "SSL verification disabled via AZURE_CLI_DISABLE_CONNECTION_VERIFICATION"
178218 )
219+ client_kwargs ["connection_verify" ] = False
220+ elif os .environ .get ("REQUESTS_CA_BUNDLE" ):
221+ ca_bundle = os .environ ["REQUESTS_CA_BUNDLE" ]
222+ logger .debug ("Using custom CA bundle: %s" , ca_bundle )
223+ client_kwargs ["connection_verify" ] = ca_bundle
179224
180225 # Return configured client
181226 return AnalyticsFrontendAPI (
182227 endpoint = api_endpoint ,
183228 api_version = api_version ,
184- authentication_policy = auth_policy
229+ authentication_policy = auth_policy ,
230+ ** client_kwargs ,
185231 )
0 commit comments