Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
70a9310
Authorization WIP
axelsrz Jun 5, 2025
cb09d3a
Sample close to completion. Testing pending.
axelsrz Jun 5, 2025
ef937b8
Merge branch 'main' of https://github.com/microsoft/Agents-for-python…
axelsrz Jun 6, 2025
71c9c88
Auth working with some sample bugs
axelsrz Jun 6, 2025
bee66dc
Sample update
axelsrz Jun 9, 2025
139f2f7
WIP. Need to reconcile MSAL client lifecycle with tentative API
axelsrz Jun 10, 2025
fdd0f07
WIP, need to complete application class changes
axelsrz Jun 13, 2025
1c49fc1
Changes code complete. Sample updates ppending
axelsrz Jun 13, 2025
c7d4da0
WIP State broken
axelsrz Jun 17, 2025
d8d157b
WIP AgentState broken
axelsrz Jun 17, 2025
03ed22b
State mostly fixed. Minor bugs pending for state, will test OBO.
axelsrz Jun 17, 2025
8fe97f0
State fixed. Testing OBO and auth handlers in routes
axelsrz Jun 17, 2025
31eed8b
Starting refactor for CloudAdapter and auth interfaces
axelsrz Jun 18, 2025
8acc045
WIP. Major object creation and configuration refactoring
axelsrz Jun 19, 2025
d8fff78
WIP gonfiguration loading dane, propagating to classes
axelsrz Jun 23, 2025
0e0b5d1
Lib changes mostly complete. Test sample pending.
axelsrz Jun 24, 2025
aaad66b
Fixed previous scenarios. Multpile handler working. MCS OBO testing g…
axelsrz Jun 26, 2025
0a77899
MCS new sample 80% working, configuration needs to be double checked
axelsrz Jun 26, 2025
7e4950f
ConversationState bug pending
axelsrz Jun 27, 2025
b15bb03
Serialization and state management fixe
axelsrz Jun 30, 2025
608c59c
Continuation activity fix
axelsrz Jul 1, 2025
060f0a4
formatting: Continuation activity fix
axelsrz Jul 1, 2025
63b065e
Multiple auth handlers working, unit tests fixed.
axelsrz Jul 1, 2025
c3c4c4b
Updating dependencies
axelsrz Jul 1, 2025
9f0a4f8
multiple handlers error path working
axelsrz Jul 2, 2025
fa0c109
Adding env template
axelsrz Jul 2, 2025
f581404
Model fixes
axelsrz Jul 7, 2025
9ca32b0
Removing sample specific configuration loading from package
axelsrz Jul 7, 2025
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,9 +1,7 @@
from .auth_types import AuthTypes
from .msal_auth_configuration import MsalAuthConfiguration
from .msal_auth import MsalAuth
from .msal_connection_manager import MsalConnectionManager

__all__ = [
"AuthTypes",
"MsalAuthConfiguration",
"MsalAuth",
"MsalConnectionManager",
]
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes

from microsoft.agents.authorization import AccessTokenProviderBase
from microsoft.agents.authorization import (
AccessTokenProviderBase,
AgentAuthConfiguration,
)

from .auth_types import AuthTypes
from .msal_auth_configuration import MsalAuthConfiguration
from microsoft.agents.authorization.auth_types import AuthTypes


class MsalAuth(AccessTokenProviderBase):

_client_credential_cache = None

def __init__(self, msal_configuration: MsalAuthConfiguration):
def __init__(self, msal_configuration: AgentAuthConfiguration):
self._msal_configuration = msal_configuration

async def get_access_token(
Expand All @@ -48,6 +50,31 @@ async def get_access_token(
# TODO: Handling token error / acquisition failed
return auth_result_payload["access_token"]

async def aquire_token_on_behalf_of(
self, scopes: list[str], user_assertion: str
) -> str:
"""
Acquire a token on behalf of a user.
:param scopes: The scopes for which to get the token.
:param user_assertion: The user assertion token.
:return: The access token as a string.
"""

msal_auth_client = self._create_client_application()
if isinstance(msal_auth_client, ManagedIdentityClient):
raise NotImplementedError(
"On-behalf-of flow is not supported with Managed Identity authentication."
)
elif isinstance(msal_auth_client, ConfidentialClientApplication):
# TODO: Handling token error / acquisition failed
return msal_auth_client.acquire_token_on_behalf_of(
user_assertion=user_assertion, scopes=scopes
)["access_token"]

raise NotImplementedError(
f"On-behalf-of flow is not supported with the current authentication type: {msal_auth_client.__class__.__name__}"
)

def _create_client_application(
self,
) -> ManagedIdentityClient | ConfidentialClientApplication:
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from typing import Dict, List, Optional
from microsoft.agents.authorization import (
AgentAuthConfiguration,
AccessTokenProviderBase,
ClaimsIdentity,
Connections,
)

from .msal_auth import MsalAuth


class MsalConnectionManager(Connections):

def __init__(
self,
connections_configurations: Dict[str, AgentAuthConfiguration] = None,
connections_map: List[Dict[str, str]] = None,
**kwargs
):
self._connections: Dict[str, MsalAuth] = {}
self._connections_map = connections_map or kwargs.get("CONNECTIONS_MAP", {})
self._service_connection_configuration: AgentAuthConfiguration = None

if connections_configurations:
for (
connection_name,
connection_settings,
) in connections_configurations.items():
self._connections[connection_name] = MsalAuth(
AgentAuthConfiguration(**connection_settings)
)
else:
raw_configurations: Dict[str, Dict] = kwargs.get("CONNECTIONS", {})
for connection_name, connection_settings in raw_configurations.items():
parsed_configuration = AgentAuthConfiguration(
**connection_settings.get("SETTINGS", {})
)
self._connections[connection_name] = MsalAuth(parsed_configuration)
if connection_name == "SERVICE_CONNECTION":
self._service_connection_configuration = parsed_configuration

if not self._connections.get("SERVICE_CONNECTION", None):
raise ValueError("No service connection configuration provided.")

def get_connection(self, connection_name: Optional[str]) -> AccessTokenProviderBase:
"""
Get the OAuth connection for the agent.
"""
return self._connections.get(connection_name, None)

def get_default_connection(self) -> AccessTokenProviderBase:
"""
Get the default OAuth connection for the agent.
"""
return self._connections.get("SERVICE_CONNECTION", None)

def get_token_provider(
self, claims_identity: ClaimsIdentity, service_url: str
) -> AccessTokenProviderBase:
"""
Get the OAuth token provider for the agent.
"""
if not self._connections_map:
return self.get_default_connection()

# TODO: Implement logic to select the appropriate connection based on the connection map

def get_default_connection_configuration(self) -> AgentAuthConfiguration:
"""
Get the default connection configuration for the agent.
"""
return self._service_connection_configuration
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from .input_file import InputFile, InputFileDownloader
from .query import Query
from .route import Route, RouteHandler
from .typing import Typing
from .typing_indicator import TypingIndicator
from .state.conversation_state import ConversationState
from .state.state import State, StatePropertyAccessor, state
from .state.temp_state import TempState
Expand All @@ -30,7 +30,7 @@
"Query",
"Route",
"RouteHandler",
"Typing",
"TypingIndicator",
"StatePropertyAccessor",
"ConversationState",
"state",
Expand Down
Loading