2323from .azure import add_sp_management_token , add_workspace_id_header
2424from .oauth import (ClientCredentials , OAuthClient , Refreshable , Token ,
2525 TokenCache , TokenSource )
26+ from .oidc_token_supplier import GitHubOIDCTokenSupplier
2627
2728CredentialsProvider = Callable [[], Dict [str , str ]]
2829
@@ -314,6 +315,44 @@ def token() -> Token:
314315 return OAuthCredentialsProvider (refreshed_headers , token )
315316
316317
318+ @oauth_credentials_strategy ("databricks-wif" , ["host" , "client_id" , "token_audience" ])
319+ def databricks_wif (cfg : "Config" ) -> Optional [CredentialsProvider ]:
320+ supplier = GitHubOIDCTokenSupplier ()
321+ # Try to get a token. If no supplier returns a token, we cannot use this authentication mode.
322+ token = supplier .get_oidc_token (cfg .token_audience )
323+ if not token :
324+ return None
325+
326+ def token_source_for (audience : str ) -> TokenSource :
327+ token = supplier .get_oidc_token (audience )
328+ if not token :
329+ # Should not happen, since we checked it above.
330+ raise Exception ("Cannot get OIDC token" )
331+ params = {
332+ "subject_token_type" : "urn:ietf:params:oauth:token-type:jwt" ,
333+ "subject_token" : token ,
334+ "grant_type" : "urn:ietf:params:oauth:grant-type:token-exchange" ,
335+ }
336+ return ClientCredentials (
337+ client_id = cfg .client_id ,
338+ client_secret = "" , # we have no (rotatable) secrets in OIDC flow
339+ token_url = cfg .oidc_endpoints .token_endpoint ,
340+ endpoint_params = params ,
341+ scopes = ["all-apis" ],
342+ use_params = True ,
343+ disable_async = not cfg .enable_experimental_async_token_refresh ,
344+ )
345+
346+ def refreshed_headers () -> Dict [str , str ]:
347+ token = token_source_for (cfg .token_audience ).token ()
348+ return {"Authorization" : f"{ token .token_type } { token .access_token } " }
349+
350+ def token () -> Token :
351+ return token_source_for (cfg .token_audience ).token ()
352+
353+ return OAuthCredentialsProvider (refreshed_headers , token )
354+
355+
317356@oauth_credentials_strategy ("github-oidc-azure" , ["host" , "azure_client_id" ])
318357def github_oidc_azure (cfg : "Config" ) -> Optional [CredentialsProvider ]:
319358 if "ACTIONS_ID_TOKEN_REQUEST_TOKEN" not in os .environ :
@@ -325,16 +364,8 @@ def github_oidc_azure(cfg: "Config") -> Optional[CredentialsProvider]:
325364 if not cfg .is_azure :
326365 return None
327366
328- # See https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-cloud-providers
329- headers = {"Authorization" : f"Bearer { os .environ ['ACTIONS_ID_TOKEN_REQUEST_TOKEN' ]} " }
330- endpoint = f"{ os .environ ['ACTIONS_ID_TOKEN_REQUEST_URL' ]} &audience=api://AzureADTokenExchange"
331- response = requests .get (endpoint , headers = headers )
332- if not response .ok :
333- return None
334-
335- # get the ID Token with aud=api://AzureADTokenExchange sub=repo:org/repo:environment:name
336- response_json = response .json ()
337- if "value" not in response_json :
367+ token = GitHubOIDCTokenSupplier ().get_oidc_token ("api://AzureADTokenExchange" )
368+ if not token :
338369 return None
339370
340371 logger .info (
@@ -344,7 +375,7 @@ def github_oidc_azure(cfg: "Config") -> Optional[CredentialsProvider]:
344375 params = {
345376 "client_assertion_type" : "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" ,
346377 "resource" : cfg .effective_azure_login_app_id ,
347- "client_assertion" : response_json [ "value" ] ,
378+ "client_assertion" : token ,
348379 }
349380 aad_endpoint = cfg .arm_environment .active_directory_endpoint
350381 if not cfg .azure_tenant_id :
@@ -927,6 +958,7 @@ def __init__(self) -> None:
927958 basic_auth ,
928959 metadata_service ,
929960 oauth_service_principal ,
961+ databricks_wif ,
930962 azure_service_principal ,
931963 github_oidc_azure ,
932964 azure_cli ,
0 commit comments