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
@@ -1,5 +1,5 @@
from typing import Dict, List, Optional
from microsoft.agents.hosting.core.authorization import (
from microsoft.agents.hosting.core import (
AgentAuthConfiguration,
AccessTokenProviderBase,
ClaimsIdentity,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import unittest
from unittest.mock import Mock
import pytest
from msal import ManagedIdentityClient, ConfidentialClientApplication
from microsoft.agents.authentication.msal import MsalAuth
from microsoft.agents.hosting.core.authorization import AgentAuthConfiguration


class TestingMsalAuth(MsalAuth):
"""
Mock object for MsalAuth
"""

def __init__(self, client_type):
super().__init__(AgentAuthConfiguration())
mock_client = Mock(spec=client_type)

mock_client.acquire_token_for_client = Mock(
return_value={"access_token": "token"}
)
mock_client.acquire_token_on_behalf_of = Mock(
return_value={"access_token": "token"}
)
self.mock_client = mock_client

self._create_client_application = Mock(return_value=self.mock_client)


class TestMsalAuth:
"""
Test suite for testing MsalAuth functionality
"""

@pytest.mark.asyncio
async def test_get_access_token_managed_identity(self):
mock_auth = TestingMsalAuth(ManagedIdentityClient)
token = await mock_auth.get_access_token(
"https://test.api.botframework.com", scopes=["test-scope"]
)

assert token == "token"
mock_auth.mock_client.acquire_token_for_client.assert_called_with(
resource="https://test.api.botframework.com"
)

@pytest.mark.asyncio
async def test_get_access_token_confidential(self):
mock_auth = TestingMsalAuth(ConfidentialClientApplication)
token = await mock_auth.get_access_token(
"https://test.api.botframework.com", scopes=["test-scope"]
)

assert token == "token"
mock_auth.mock_client.acquire_token_for_client.assert_called_with(
scopes=["test-scope"]
)

@pytest.mark.asyncio
async def test_aquire_token_on_behalf_of_managed_identity(self):
mock_auth = TestingMsalAuth(ManagedIdentityClient)

try:
await mock_auth.aquire_token_on_behalf_of(
scopes=["test-scope"], user_assertion="test-assertion"
)
except NotImplementedError:
assert True
else:
assert False

@pytest.mark.asyncio
async def test_aquire_token_on_behalf_of_confidential(self):
mock_auth = TestingMsalAuth(ConfidentialClientApplication)
mock_auth._create_client_application = Mock(return_value=mock_auth.mock_client)

token = await mock_auth.aquire_token_on_behalf_of(
scopes=["test-scope"], user_assertion="test-assertion"
)

assert token == "token"
mock_auth.mock_client.acquire_token_on_behalf_of.assert_called_with(
scopes=["test-scope"], user_assertion="test-assertion"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from os import environ
from microsoft.agents.activity import load_configuration_from_env
from microsoft.agents.hosting.core import AuthTypes
from microsoft.agents.authentication.msal import MsalConnectionManager


class TestMsalConnectionManager:
"""
Test suite for the Msal Connection Manager
"""

def test_msal_connection_manager(self):
mock_environ = {
**environ,
"CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID": "test-tenant-id-SERVICE_CONNECTION",
"CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID": "test-client-id-SERVICE_CONNECTION",
"CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET": "test-client-secret-SERVICE_CONNECTION",
"CONNECTIONS__MCS__SETTINGS__TENANTID": "test-tenant-id-MCS",
"CONNECTIONS__MCS__SETTINGS__CLIENTID": "test-client-id-MCS",
"CONNECTIONS__MCS__SETTINGS__CLIENTSECRET": "test-client-secret-MCS",
}

config = load_configuration_from_env(mock_environ)
connection_manager = MsalConnectionManager(**config)
for key in connection_manager._connections:
auth = connection_manager.get_connection(key)._msal_configuration
assert auth.AUTH_TYPE == AuthTypes.client_secret
assert auth.CLIENT_ID == f"test-client-id-{key}"
assert auth.TENANT_ID == f"test-tenant-id-{key}"
assert auth.CLIENT_SECRET == f"test-client-secret-{key}"
assert auth.ISSUERS == [
"https://api.botframework.com",
f"https://sts.windows.net/test-tenant-id-{key}/",
f"https://login.microsoftonline.com/test-tenant-id-{key}/v2.0",
]
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ async def _on_error(self, context: TurnContext, err: ApplicationError) -> None:
)
return await self._error(context, err)

ogger.error(
logger.error(
f"An error occurred in the AgentApplication: {err}",
exc_info=True,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,19 +124,16 @@ def __init__(
else auth_configuration.get("AUTOSIGNIN", False)
)

if not auth_handlers:
handlers_congif: Dict[str, Dict] = auth_configuration.get("HANDLERS")
if not handlers_congif:
logger.error("No auth handlers provided in configuration")
raise ValueError("The authorization does not have any auth handlers")
handlers_config: Dict[str, Dict] = auth_configuration.get("HANDLERS")
if not auth_handlers and handlers_config:
auth_handlers = {
handler_name: AuthHandler(
name=handler_name, **config.get("SETTINGS", {})
)
for handler_name, config in handlers_congif.items()
for handler_name, config in handlers_config.items()
}

self._auth_handlers = auth_handlers
self._auth_handlers = auth_handlers or {}
self._sign_in_handler: Optional[
Callable[[TurnContext, TurnState, Optional[str]], Awaitable[None]]
] = None
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from os import environ
from typing import Dict
from microsoft.agents.activity import load_configuration_from_env
from microsoft.agents.hosting.core import AgentAuthConfiguration, AuthTypes


class TestAuthorizationConfiguration:
"""
Unit tests to validate Authorization Configuration cases
"""

def test_auth_configuration_basic(self):
# test AgentAuthConfiguration with manual insertion of fields
auth_config = AgentAuthConfiguration(
auth_type=AuthTypes.client_secret,
tenant_id="test-tenant-id",
client_id="test-client-id",
client_secret="test-client-secret",
cert_pem_file="test-cert.pem",
cert_key_file="test-cert.key",
connection_name="test-connection",
authority="https://login.microsoftonline.com",
scopes=["test-scope-1", "test-scope-2"],
)

assert auth_config.AUTH_TYPE == AuthTypes.client_secret
assert auth_config.TENANT_ID == "test-tenant-id"
assert auth_config.CLIENT_ID == "test-client-id"
assert auth_config.CLIENT_SECRET == "test-client-secret"
assert auth_config.CERT_PEM_FILE == "test-cert.pem"
assert auth_config.CERT_KEY_FILE == "test-cert.key"
assert auth_config.CONNECTION_NAME == "test-connection"
assert auth_config.AUTHORITY == "https://login.microsoftonline.com"
assert auth_config.SCOPES == ["test-scope-1", "test-scope-2"]
assert auth_config.ISSUERS == [
"https://api.botframework.com",
f"https://sts.windows.net/test-tenant-id/",
f"https://login.microsoftonline.com/test-tenant-id/v2.0",
]

def test_load_configuration_from_env(self):
# test load_configuration_from_env, passed to AgentAuthConfiguration
mock_environ = {
**environ,
"CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID": "test-tenant-id-SERVICE_CONNECTION",
"CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID": "test-client-id-SERVICE_CONNECTION",
"CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET": "test-client-secret-SERVICE_CONNECTION",
"CONNECTIONS__MCS__SETTINGS__TENANTID": "test-tenant-id-MCS",
"CONNECTIONS__MCS__SETTINGS__CLIENTID": "test-client-id-MCS",
"CONNECTIONS__MCS__SETTINGS__CLIENTSECRET": "test-client-secret-MCS",
}

mock_config = load_configuration_from_env(mock_environ)

raw_configurations: Dict[str, Dict] = mock_config.get("CONNECTIONS", {})

for name, settings in raw_configurations.items():
auth_config = AgentAuthConfiguration(**settings["SETTINGS"])
assert auth_config.AUTH_TYPE == AuthTypes.client_secret
assert auth_config.CLIENT_ID == f"test-client-id-{name}"
assert auth_config.TENANT_ID == f"test-tenant-id-{name}"
assert auth_config.CLIENT_SECRET == f"test-client-secret-{name}"
assert auth_config.ISSUERS == [
"https://api.botframework.com",
f"https://sts.windows.net/test-tenant-id-{name}/",
f"https://login.microsoftonline.com/test-tenant-id-{name}/v2.0",
]

def test_empty_settings(self):
auth_config = AgentAuthConfiguration()
assert auth_config.AUTH_TYPE == AuthTypes.client_secret
assert auth_config.TENANT_ID == None
assert auth_config.CLIENT_ID == None
assert auth_config.CLIENT_SECRET == None
assert auth_config.CERT_PEM_FILE == None
assert auth_config.CERT_KEY_FILE == None
assert auth_config.CONNECTION_NAME == None
assert auth_config.AUTHORITY == None
assert auth_config.SCOPES == None
Loading