From 75c91c8e0afb15d2a9a5285405dd6b686ace4ed0 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 18 Aug 2026 14:56:18 -0700 Subject: [PATCH 1/5] AgentAuthConfiguration validation --- .../authorization/agent_auth_configuration.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py index c9edd1d5..1314323b 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py @@ -222,6 +222,29 @@ def __init__( # JWT-patch: always at least include self for backward compat self._connections = {str(self.CONNECTION_NAME): self} + self._validate() + + def _validate(self) -> None: + """ + Validates the configuration. Raises ValueError if any required fields are missing or invalid. + """ + if self.AUTH_TYPE == AuthTypes.client_secret and not self.CLIENT_SECRET: + raise ValueError( + "CLIENT_SECRET is required for client_secret authentication." + ) + if self.AUTH_TYPE == AuthTypes.certificate and not self.CERT_PFX_FILE: + raise ValueError( + "CERT_PFX_FILE is required for certificate authentication." + ) + if self.AUTH_TYPE == AuthTypes.identity_proxy_manager and not self.IDPM_RESOURCE: + raise ValueError( + "IDPM_RESOURCE is required for identity_proxy_manager authentication." + ) + if self.AUTH_TYPE == AuthTypes.federated_credentials and not self.FEDERATED_CLIENT_ID: + raise ValueError( + "FEDERATED_CLIENT_ID is required for federated_credentials authentication." + ) + @property def ISSUERS(self) -> list[str]: """ From d872feaab5fac46981a77a7bbe9339e6ac7cfdde Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 18 Aug 2026 14:57:51 -0700 Subject: [PATCH 2/5] Removed CLIENT_SECRET check --- .../hosting/core/authorization/agent_auth_configuration.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py index 1314323b..3439a47e 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py @@ -228,10 +228,6 @@ def _validate(self) -> None: """ Validates the configuration. Raises ValueError if any required fields are missing or invalid. """ - if self.AUTH_TYPE == AuthTypes.client_secret and not self.CLIENT_SECRET: - raise ValueError( - "CLIENT_SECRET is required for client_secret authentication." - ) if self.AUTH_TYPE == AuthTypes.certificate and not self.CERT_PFX_FILE: raise ValueError( "CERT_PFX_FILE is required for certificate authentication." From 965bf856e51dc46d4b3df604937c418481c8bb2e Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 18 Aug 2026 15:01:38 -0700 Subject: [PATCH 3/5] Adding tests --- .../authorization/agent_auth_configuration.py | 9 +++-- tests/hosting_core/test_auth_configuration.py | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py index 3439a47e..d0a266f4 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py @@ -232,11 +232,10 @@ def _validate(self) -> None: raise ValueError( "CERT_PFX_FILE is required for certificate authentication." ) - if self.AUTH_TYPE == AuthTypes.identity_proxy_manager and not self.IDPM_RESOURCE: - raise ValueError( - "IDPM_RESOURCE is required for identity_proxy_manager authentication." - ) - if self.AUTH_TYPE == AuthTypes.federated_credentials and not self.FEDERATED_CLIENT_ID: + if ( + self.AUTH_TYPE == AuthTypes.federated_credentials + and not self.FEDERATED_CLIENT_ID + ): raise ValueError( "FEDERATED_CLIENT_ID is required for federated_credentials authentication." ) diff --git a/tests/hosting_core/test_auth_configuration.py b/tests/hosting_core/test_auth_configuration.py index 03d27e5e..dac5ac4f 100644 --- a/tests/hosting_core/test_auth_configuration.py +++ b/tests/hosting_core/test_auth_configuration.py @@ -1,4 +1,7 @@ from os import environ + +import pytest + from microsoft_agents.activity import load_configuration_from_env from microsoft_agents.hosting.core import AgentAuthConfiguration, AuthTypes @@ -102,6 +105,39 @@ def test_empty_settings(self): assert auth_config.SCOPES is None assert auth_config.AZURE_REGION is None + @pytest.mark.parametrize( + ("auth_type", "expected_message"), + [ + ( + AuthTypes.certificate, + "CERT_PFX_FILE is required for certificate authentication.", + ), + ( + AuthTypes.federated_credentials, + "FEDERATED_CLIENT_ID is required for " + "federated_credentials authentication.", + ), + ], + ) + def test_auth_type_requires_credential_setting(self, auth_type, expected_message): + with pytest.raises(ValueError, match=expected_message): + AgentAuthConfiguration(auth_type=auth_type) + + @pytest.mark.parametrize( + ("auth_type", "credential"), + [ + (AuthTypes.certificate, {"cert_pfx_file": "test-cert.pfx"}), + ( + AuthTypes.federated_credentials, + {"federated_client_id": "test-federated-client-id"}, + ), + ], + ) + def test_auth_type_accepts_required_credential_setting(self, auth_type, credential): + auth_config = AgentAuthConfiguration(auth_type=auth_type, **credential) + + assert auth_config.AUTH_TYPE == auth_type + def test_workload_identity_token_file_from_kwargs(self): auth_config = AgentAuthConfiguration( AUTHTYPE="WorkloadIdentity", From 231e834ced83f6ca544c1c8a515b260e4831a884 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 18 Aug 2026 15:04:49 -0700 Subject: [PATCH 4/5] Updating changelog --- changelog.md | 11 +++++++++++ tests/authentication_msal/test_msal_auth.py | 17 ++++++++--------- tests/hosting_core/test_auth_configuration.py | 9 +++++++++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 98be155d..f8d47dfe 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,14 @@ +# Microsoft 365 Agents SDK for Python - Release Notes v1.5.0 (Unreleased) + +**Release Date:** Unreleased +**Previous Version:** 1.4.0 (Released 2026-08-18) + +## Developer Experience + +- **Authentication Configuration Validation**: Added validation for certificate, federated credential, and workload identity authentication settings + +--- + # Microsoft 365 Agents SDK for Python - Release Notes v1.4.0 **Release Date:** 2026-08-18 diff --git a/tests/authentication_msal/test_msal_auth.py b/tests/authentication_msal/test_msal_auth.py index df51242e..7aa00094 100644 --- a/tests/authentication_msal/test_msal_auth.py +++ b/tests/authentication_msal/test_msal_auth.py @@ -284,17 +284,16 @@ def test_create_client_application_reads_projected_token(self, mocker, tmp_path) token_file.write_text("\trefreshed-token\n", encoding="utf-8") assert client_assertion() == "refreshed-token" - def test_create_client_application_requires_token_file(self): - config = AgentAuthConfiguration( - auth_type=AuthTypes.workload_identity, - tenant_id="12345678-1234-1234-1234-123456789abc", - client_id="test-client-id", - ) - + def test_configuration_requires_token_file(self): with pytest.raises( - ValueError, match="FEDERATED_TOKEN_FILE must be set in configuration" + ValueError, + match="FEDERATED_TOKEN_FILE is required for workload_identity authentication", ): - MsalAuth(config)._create_client_application() + AgentAuthConfiguration( + auth_type=AuthTypes.workload_identity, + tenant_id="12345678-1234-1234-1234-123456789abc", + client_id="test-client-id", + ) class TestMsalAuthIdentityProxyManager: diff --git a/tests/hosting_core/test_auth_configuration.py b/tests/hosting_core/test_auth_configuration.py index dac5ac4f..aa1b8863 100644 --- a/tests/hosting_core/test_auth_configuration.py +++ b/tests/hosting_core/test_auth_configuration.py @@ -117,6 +117,11 @@ def test_empty_settings(self): "FEDERATED_CLIENT_ID is required for " "federated_credentials authentication.", ), + ( + AuthTypes.workload_identity, + "FEDERATED_TOKEN_FILE is required for " + "workload_identity authentication.", + ), ], ) def test_auth_type_requires_credential_setting(self, auth_type, expected_message): @@ -131,6 +136,10 @@ def test_auth_type_requires_credential_setting(self, auth_type, expected_message AuthTypes.federated_credentials, {"federated_client_id": "test-federated-client-id"}, ), + ( + AuthTypes.workload_identity, + {"federated_token_file": "test-token-file"}, + ), ], ) def test_auth_type_accepts_required_credential_setting(self, auth_type, credential): From 4b1c02098f9d70d4eed55f789aa6d18b4ee0c1cf Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 18 Aug 2026 15:10:03 -0700 Subject: [PATCH 5/5] Updating validation logic --- .../hosting/core/authorization/agent_auth_configuration.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py index d0a266f4..c94a953f 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py @@ -239,6 +239,13 @@ def _validate(self) -> None: raise ValueError( "FEDERATED_CLIENT_ID is required for federated_credentials authentication." ) + if ( + self.AUTH_TYPE == AuthTypes.workload_identity + and not self.FEDERATED_TOKEN_FILE + ): + raise ValueError( + "FEDERATED_TOKEN_FILE is required for workload_identity authentication." + ) @property def ISSUERS(self) -> list[str]: