Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/ContentProcessor/src/libs/utils/azure_credential_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def get_async_bearer_token_provider():
Returns:
A callable suitable for SDK clients that accept a token provider.
"""
credential = await get_async_azure_credential()
credential = get_async_azure_credential()
return identity_get_async_bearer_token_provider(
credential, "https://cognitiveservices.azure.com/.default"
)
Expand Down Expand Up @@ -191,11 +191,24 @@ def get_async_azure_credential():
logging.info(f"[AUTH] Using {credential_name} for local development")
return credential

# Final fallback to DefaultAzureCredential
app_env = os.getenv("APP_ENV", "prod").lower()
if app_env == "prod":
client_id = os.getenv("AZURE_CLIENT_ID")
if client_id:
logging.info(
"[AUTH] APP_ENV=prod -> using async user-assigned managed identity: %s",
client_id,
)
return AsyncManagedIdentityCredential(client_id=client_id)
logging.info(
"[AUTH] APP_ENV=prod -> using async system-assigned managed identity"
)
return AsyncManagedIdentityCredential()

logging.info(
"[AUTH] All async CLI credentials failed - falling back to AsyncDefaultAzureCredential"
"[AUTH] APP_ENV=%s -> falling back to AsyncDefaultAzureCredential", app_env
)
return AsyncDefaultAzureCredential()
return AsyncDefaultAzureCredential() # CodeQL [SM05139] Okay use of DefaultAzureCredential as it is only used in development


def validate_azure_authentication() -> dict[str, Any]:
Expand Down
2 changes: 1 addition & 1 deletion src/ContentProcessor/src/libs/utils/credential_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def get_async_bearer_token_provider():
Returns:
A callable suitable for SDK clients that accept a token provider.
"""
credential = await get_async_azure_credential()
credential = get_async_azure_credential()
return identity_get_async_bearer_token_provider(
credential, "https://cognitiveservices.azure.com/.default"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def test_returns_async_user_assigned_with_client_id(self, mock_async_managed):
side_effect=Exception("no azd"),
)
@patch(f"{MODULE}.AsyncAzureCliCredential", side_effect=Exception("no az"))
@patch.dict("os.environ", {}, clear=True)
@patch.dict("os.environ", {"APP_ENV": "dev"}, clear=True)
def test_falls_back_to_async_default(
self, mock_async_cli, mock_async_dev_cli, mock_async_default
):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def test_get_async_azure_credential_cli_fallback(self, monkeypatch):
for key in ["WEBSITE_SITE_NAME", "AZURE_CLIENT_ID", "MSI_ENDPOINT",
"IDENTITY_ENDPOINT", "KUBERNETES_SERVICE_HOST"]:
monkeypatch.delenv(key, raising=False)
monkeypatch.setenv("APP_ENV", "dev")

with patch('libs.utils.azure_credential_utils.AsyncAzureCliCredential') as mock_cli, \
patch('libs.utils.azure_credential_utils.AsyncAzureDeveloperCliCredential') as mock_azd, \
Expand Down Expand Up @@ -149,10 +150,7 @@ async def test_get_async_bearer_token_provider_success(self, monkeypatch):
"""Test async bearer token provider creation"""
monkeypatch.setenv("MSI_ENDPOINT", "http://localhost")

# Create an async mock
from unittest.mock import AsyncMock

with patch('libs.utils.azure_credential_utils.get_async_azure_credential', new_callable=AsyncMock) as mock_get_cred, \
with patch('libs.utils.azure_credential_utils.get_async_azure_credential') as mock_get_cred, \
patch('libs.utils.azure_credential_utils.identity_get_async_bearer_token_provider') as mock_provider:

mock_credential = Mock()
Expand Down