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
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ async def _async_acquire_token_for_client(msal_auth_client, *args, **kwargs):

class MsalAuth(AccessTokenProviderBase):

_client_credential_cache = None

def __init__(self, msal_configuration: AgentAuthConfiguration):
"""Initializes the MsalAuth class with the given configuration.

Expand Down Expand Up @@ -211,16 +209,38 @@ def _create_client_application(
)
else:
authority = MsalAuth._resolve_authority(self._msal_configuration, tenant_id)
client_credential = None

if self._client_credential_cache:
logger.info("Using cached client credentials for MSAL authentication.")
pass
elif self._msal_configuration.AUTH_TYPE == AuthTypes.client_secret:
self._client_credential_cache = self._msal_configuration.CLIENT_SECRET
if self._msal_configuration.AUTH_TYPE == AuthTypes.client_secret:
client_credential = self._msal_configuration.CLIENT_SECRET
elif self._msal_configuration.AUTH_TYPE == AuthTypes.certificate:
self._client_credential_cache = {
client_credential = {
"private_key_pfx_path": self._msal_configuration.CERT_PFX_FILE,
}
elif self._msal_configuration.AUTH_TYPE == AuthTypes.federated_credentials:
mi_client = ManagedIdentityClient(
UserAssignedManagedIdentity(
client_id=self._msal_configuration.FEDERATED_CLIENT_ID
Comment thread
rodrigobr-msft marked this conversation as resolved.
),
http_client=Session(),
)

def get_assertion() -> str:
result = mi_client.acquire_token_for_client(
resource="api://AzureADTokenExchange"
)
Comment thread
rodrigobr-msft marked this conversation as resolved.
Comment thread
rodrigobr-msft marked this conversation as resolved.
if "access_token" not in result:
logger.error(
f"Failed to acquire token for federated credentials: {result}"
)
raise ValueError(
authentication_errors.FailedToAcquireToken.format(
str(result)
)
)
return result["access_token"]

client_credential = {"client_assertion": get_assertion}
Comment thread
rodrigobr-msft marked this conversation as resolved.
Comment thread
rodrigobr-msft marked this conversation as resolved.
else:
logger.error(
f"Unsupported authentication type: {self._msal_configuration.AUTH_TYPE}"
Expand All @@ -232,7 +252,7 @@ def _create_client_application(
return ConfidentialClientApplication(
client_id=self._msal_configuration.CLIENT_ID,
authority=authority,
client_credential=self._client_credential_cache,
client_credential=client_credential,
)

def _client_rep(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# Licensed under the MIT License.

from __future__ import annotations
from typing import Optional

from microsoft_agents.hosting.core.authorization.auth_types import AuthTypes

Expand All @@ -17,20 +16,22 @@ class AgentAuthConfiguration:
CLIENT_SECRET: The client secret for the Azure AD application (if using client secret authentication).
CERT_PFX_FILE: The path to the PFX certificate file (if using certificate authentication).
CONNECTION_NAME: The name of the connection
FEDERATED_CLIENT_ID: The client ID for federated credentials (if using federated credentials authentication).
SCOPES: The scopes to request
AUTHORITY: The authority URL for the Azure AD (if different from the default).
ALT_BLUEPRINT_ID: An optional alternative blueprint ID used when constructing a connector client.
"""

TENANT_ID: Optional[str]
TENANT_ID: str | None
AUTH_TYPE: AuthTypes
CLIENT_ID: Optional[str]
CLIENT_SECRET: Optional[str]
CERT_PFX_FILE: Optional[str]
CONNECTION_NAME: Optional[str]
SCOPES: Optional[list[str]]
AUTHORITY: Optional[str]
ALT_BLUEPRINT_ID: Optional[str]
CLIENT_ID: str | None
CLIENT_SECRET: str | None
CERT_PFX_FILE: str | None
CONNECTION_NAME: str | None
FEDERATED_CLIENT_ID: str | None
SCOPES: list[str] | None
AUTHORITY: str | None
ALT_BLUEPRINT_ID: str | None
ANONYMOUS_ALLOWED: bool = False

# Multi-connection support: Maintains a map of all configured connections
Expand All @@ -50,6 +51,7 @@ def __init__(
client_secret: str | None = None,
cert_pfx_file: str | None = None,
connection_name: str | None = None,
federated_client_id: str | None = None,
authority: str | None = None,
scopes: list[str] | None = None,
anonymous_allowed: bool = False,
Expand All @@ -63,6 +65,9 @@ def __init__(
self.CLIENT_SECRET = client_secret or kwargs.get("CLIENTSECRET", None)
self.CERT_PFX_FILE = cert_pfx_file or kwargs.get("CERTPFXFILE", None)
self.CONNECTION_NAME = connection_name or kwargs.get("CONNECTIONNAME", None)
self.FEDERATED_CLIENT_ID = federated_client_id or kwargs.get(
"FEDERATEDCLIENTID", None
)
self.SCOPES = scopes or kwargs.get("SCOPES", None)
self.ALT_BLUEPRINT_ID = kwargs.get("ALT_BLUEPRINT_NAME", None)
self.ANONYMOUS_ALLOWED = anonymous_allowed or kwargs.get(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ class AuthTypes(str, Enum):
client_secret = "ClientSecret"
user_managed_identity = "UserManagedIdentity"
system_managed_identity = "SystemManagedIdentity"
federated_credentials = "FederatedCredentials"
1 change: 1 addition & 0 deletions tests/hosting_core/test_auth_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def test_empty_settings(self):
assert auth_config.CLIENT_ID is None
assert auth_config.CLIENT_SECRET is None
assert auth_config.CERT_PFX_FILE is None
assert auth_config.FEDERATED_CLIENT_ID is None
assert auth_config.CONNECTION_NAME is None
assert auth_config.AUTHORITY is None
assert auth_config.SCOPES is None
Loading