diff --git a/README.md b/README.md index aedd0482b..92a7c1332 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ For more information jump to a section below. | Branch | Description | Build Status | Coverage Status | Code Style | |----|---------------|--------------|-----------------|--| -| Main | 4.16.0 Builds | [![Build Status](https://fuselabs.visualstudio.com/SDK_v4/_apis/build/status/Python/Python-CI-PR-yaml?branchName=main)](https://fuselabs.visualstudio.com/SDK_v4/_build/latest?definitionId=771&branchName=main) | [![Coverage Status](https://coveralls.io/repos/github/microsoft/botbuilder-python/badge.svg?branch=HEAD)](https://coveralls.io/github/microsoft/botbuilder-python?branch=HEAD) | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | +| Main | 4.17.0 Builds | [![Build Status](https://fuselabs.visualstudio.com/SDK_v4/_apis/build/status/Python/Python-CI-PR-yaml?branchName=main)](https://fuselabs.visualstudio.com/SDK_v4/_build/latest?definitionId=771&branchName=main) | [![Coverage Status](https://coveralls.io/repos/github/microsoft/botbuilder-python/badge.svg?branch=HEAD)](https://coveralls.io/github/microsoft/botbuilder-python?branch=HEAD) | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | ## Packages diff --git a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/about.py b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/about.py index 2da3fe8e7..d0c18dbaa 100644 --- a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/about.py +++ b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/about.py @@ -5,7 +5,7 @@ __title__ = "botbuilder-adapters-slack" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-adapters-slack/requirements.txt b/libraries/botbuilder-adapters-slack/requirements.txt index 7fd82d816..8d2c7b043 100644 --- a/libraries/botbuilder-adapters-slack/requirements.txt +++ b/libraries/botbuilder-adapters-slack/requirements.txt @@ -1,4 +1,4 @@ aiohttp==3.9.5 pyslack -botbuilder-core==4.16.0 +botbuilder-core==4.17.0 slackclient diff --git a/libraries/botbuilder-adapters-slack/setup.py b/libraries/botbuilder-adapters-slack/setup.py index d3eb8cbd1..25fc99ed8 100644 --- a/libraries/botbuilder-adapters-slack/setup.py +++ b/libraries/botbuilder-adapters-slack/setup.py @@ -5,9 +5,9 @@ from setuptools import setup REQUIRES = [ - "botbuilder-schema==4.16.0", - "botframework-connector==4.16.0", - "botbuilder-core==4.16.0", + "botbuilder-schema==4.17.0", + "botframework-connector==4.17.0", + "botbuilder-core==4.17.0", "pyslack", "slackclient", ] diff --git a/libraries/botbuilder-ai/botbuilder/ai/about.py b/libraries/botbuilder-ai/botbuilder/ai/about.py index 22d69d517..e063c5499 100644 --- a/libraries/botbuilder-ai/botbuilder/ai/about.py +++ b/libraries/botbuilder-ai/botbuilder/ai/about.py @@ -5,7 +5,7 @@ __title__ = "botbuilder-ai" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-ai/requirements.txt b/libraries/botbuilder-ai/requirements.txt index cea1e6ded..232724deb 100644 --- a/libraries/botbuilder-ai/requirements.txt +++ b/libraries/botbuilder-ai/requirements.txt @@ -1,6 +1,6 @@ msrest== 0.7.* -botbuilder-schema==4.16.0 -botbuilder-core==4.16.0 +botbuilder-schema==4.17.0 +botbuilder-core==4.17.0 requests==2.32.0 aiounittest==1.3.0 azure-cognitiveservices-language-luis==0.2.0 \ No newline at end of file diff --git a/libraries/botbuilder-ai/setup.py b/libraries/botbuilder-ai/setup.py index bd954661b..105f1a4c9 100644 --- a/libraries/botbuilder-ai/setup.py +++ b/libraries/botbuilder-ai/setup.py @@ -6,8 +6,8 @@ REQUIRES = [ "azure-cognitiveservices-language-luis==0.2.0", - "botbuilder-schema==4.16.0", - "botbuilder-core==4.16.0", + "botbuilder-schema==4.17.0", + "botbuilder-core==4.17.0", "aiohttp==3.9.5", ] diff --git a/libraries/botbuilder-applicationinsights/botbuilder/applicationinsights/about.py b/libraries/botbuilder-applicationinsights/botbuilder/applicationinsights/about.py index 74f9edbb5..b36e7c9b3 100644 --- a/libraries/botbuilder-applicationinsights/botbuilder/applicationinsights/about.py +++ b/libraries/botbuilder-applicationinsights/botbuilder/applicationinsights/about.py @@ -6,7 +6,7 @@ __title__ = "botbuilder-applicationinsights" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-applicationinsights/requirements.txt b/libraries/botbuilder-applicationinsights/requirements.txt index dd908fd7c..dcdbb2ecb 100644 --- a/libraries/botbuilder-applicationinsights/requirements.txt +++ b/libraries/botbuilder-applicationinsights/requirements.txt @@ -1,3 +1,3 @@ msrest== 0.7.* -botbuilder-core==4.16.0 +botbuilder-core==4.17.0 aiounittest==1.3.0 \ No newline at end of file diff --git a/libraries/botbuilder-applicationinsights/setup.py b/libraries/botbuilder-applicationinsights/setup.py index 8b9dc8107..0932ff98f 100644 --- a/libraries/botbuilder-applicationinsights/setup.py +++ b/libraries/botbuilder-applicationinsights/setup.py @@ -6,9 +6,9 @@ REQUIRES = [ "applicationinsights==0.11.9", - "botbuilder-schema==4.16.0", - "botframework-connector==4.16.0", - "botbuilder-core==4.16.0", + "botbuilder-schema==4.17.0", + "botframework-connector==4.17.0", + "botbuilder-core==4.17.0", ] TESTS_REQUIRES = [ "aiounittest==1.3.0", diff --git a/libraries/botbuilder-azure/botbuilder/azure/about.py b/libraries/botbuilder-azure/botbuilder/azure/about.py index 73d05308a..2b8d35387 100644 --- a/libraries/botbuilder-azure/botbuilder/azure/about.py +++ b/libraries/botbuilder-azure/botbuilder/azure/about.py @@ -5,7 +5,7 @@ __title__ = "botbuilder-azure" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-azure/setup.py b/libraries/botbuilder-azure/setup.py index 85b4bf5e5..04fd479cb 100644 --- a/libraries/botbuilder-azure/setup.py +++ b/libraries/botbuilder-azure/setup.py @@ -8,8 +8,8 @@ "azure-cosmos==3.2.0", "azure-storage-blob==12.7.0", "azure-storage-queue==12.4.0", - "botbuilder-schema==4.16.0", - "botframework-connector==4.16.0", + "botbuilder-schema==4.17.0", + "botframework-connector==4.17.0", "jsonpickle>=1.2,<1.5", ] TEST_REQUIRES = ["aiounittest==1.3.0"] diff --git a/libraries/botbuilder-core/botbuilder/core/about.py b/libraries/botbuilder-core/botbuilder/core/about.py index b684dfef7..5220c09e6 100644 --- a/libraries/botbuilder-core/botbuilder/core/about.py +++ b/libraries/botbuilder-core/botbuilder/core/about.py @@ -5,7 +5,7 @@ __title__ = "botbuilder-core" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-core/botbuilder/core/channel_service_handler.py b/libraries/botbuilder-core/botbuilder/core/channel_service_handler.py index 8de4da56d..2b819d00c 100644 --- a/libraries/botbuilder-core/botbuilder/core/channel_service_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/channel_service_handler.py @@ -504,7 +504,9 @@ async def _authenticate(self, auth_header: str) -> ClaimsIdentity: ) if not is_auth_disabled: # No auth header. Auth is required. Request is not authorized. - raise PermissionError() + raise PermissionError( + "Authorization is required but has been disabled." + ) # In the scenario where Auth is disabled, we still want to have the # IsAuthenticated flag set in the ClaimsIdentity. To do this requires diff --git a/libraries/botbuilder-core/requirements.txt b/libraries/botbuilder-core/requirements.txt index d9a4bc2f1..6ce30f68f 100644 --- a/libraries/botbuilder-core/requirements.txt +++ b/libraries/botbuilder-core/requirements.txt @@ -1,7 +1,7 @@ msrest== 0.7.* -botframework-connector==4.16.0 -botbuilder-schema==4.16.0 -botframework-streaming==4.16.0 +botframework-connector==4.17.0 +botbuilder-schema==4.17.0 +botframework-streaming==4.17.0 requests==2.32.0 PyJWT==2.4.0 cryptography==42.0.4 diff --git a/libraries/botbuilder-core/setup.py b/libraries/botbuilder-core/setup.py index 6b4ec5929..a4a0ed1af 100644 --- a/libraries/botbuilder-core/setup.py +++ b/libraries/botbuilder-core/setup.py @@ -4,11 +4,11 @@ import os from setuptools import setup -VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" +VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" REQUIRES = [ - "botbuilder-schema==4.16.0", - "botframework-connector==4.16.0", - "botframework-streaming==4.16.0", + "botbuilder-schema==4.17.0", + "botframework-connector==4.17.0", + "botframework-streaming==4.17.0", "jsonpickle>=1.2,<1.5", ] diff --git a/libraries/botbuilder-dialogs/botbuilder/dialogs/about.py b/libraries/botbuilder-dialogs/botbuilder/dialogs/about.py index ac3c0bd7f..5885a1a1e 100644 --- a/libraries/botbuilder-dialogs/botbuilder/dialogs/about.py +++ b/libraries/botbuilder-dialogs/botbuilder/dialogs/about.py @@ -5,7 +5,7 @@ __title__ = "botbuilder-dialogs" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-dialogs/requirements.txt b/libraries/botbuilder-dialogs/requirements.txt index 2ee28a093..920200124 100644 --- a/libraries/botbuilder-dialogs/requirements.txt +++ b/libraries/botbuilder-dialogs/requirements.txt @@ -1,7 +1,7 @@ msrest== 0.7.* -botframework-connector==4.16.0 -botbuilder-schema==4.16.0 -botbuilder-core==4.16.0 +botframework-connector==4.17.0 +botbuilder-schema==4.17.0 +botbuilder-core==4.17.0 requests==2.32.0 PyJWT==2.4.0 cryptography==42.0.4 diff --git a/libraries/botbuilder-dialogs/setup.py b/libraries/botbuilder-dialogs/setup.py index 8b2a44a27..8cedaa53c 100644 --- a/libraries/botbuilder-dialogs/setup.py +++ b/libraries/botbuilder-dialogs/setup.py @@ -13,9 +13,9 @@ "recognizers-text>=1.0.2a1", "recognizers-text-choice>=1.0.2a1", "babel==2.9.1", - "botbuilder-schema==4.16.0", - "botframework-connector==4.16.0", - "botbuilder-core==4.16.0", + "botbuilder-schema==4.17.0", + "botframework-connector==4.17.0", + "botbuilder-core==4.17.0", ] TEST_REQUIRES = ["aiounittest==1.3.0"] diff --git a/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/about.py b/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/about.py index fd45f9491..e5cd51eee 100644 --- a/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/about.py +++ b/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/about.py @@ -5,7 +5,7 @@ __title__ = "botbuilder-integration-aiohttp" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/cloud_adapter.py b/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/cloud_adapter.py index 0aa2ba8af..0f9131871 100644 --- a/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/cloud_adapter.py +++ b/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/cloud_adapter.py @@ -107,7 +107,7 @@ async def process( return Response(status=201) else: raise HTTPMethodNotAllowed - except (HTTPUnauthorized, PermissionError) as _: + except PermissionError: raise HTTPUnauthorized async def _connect( diff --git a/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/configuration_service_client_credential_factory.py b/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/configuration_service_client_credential_factory.py index 34e7c7644..6379e16b6 100644 --- a/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/configuration_service_client_credential_factory.py +++ b/libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/configuration_service_client_credential_factory.py @@ -4,18 +4,23 @@ from logging import Logger from typing import Any +from msrest.authentication import Authentication + from botframework.connector.auth import PasswordServiceClientCredentialFactory +from botframework.connector.auth import ManagedIdentityServiceClientCredentialsFactory +from botframework.connector.auth import ServiceClientCredentialsFactory -class ConfigurationServiceClientCredentialFactory( - PasswordServiceClientCredentialFactory -): +class ConfigurationServiceClientCredentialFactory(ServiceClientCredentialsFactory): def __init__(self, configuration: Any, *, logger: Logger = None) -> None: + self._inner = None + app_type = ( configuration.APP_TYPE if hasattr(configuration, "APP_TYPE") else "MultiTenant" - ) + ).lower() + app_id = configuration.APP_ID if hasattr(configuration, "APP_ID") else None app_password = ( configuration.APP_PASSWORD @@ -24,10 +29,25 @@ def __init__(self, configuration: Any, *, logger: Logger = None) -> None: ) app_tenantid = None - if app_type == "UserAssignedMsi": - raise Exception("UserAssignedMsi APP_TYPE is not supported") + if app_type == "userassignedmsi": + if not app_id: + raise Exception("Property 'APP_ID' is expected in configuration object") + + app_tenantid = ( + configuration.APP_TENANTID + if hasattr(configuration, "APP_TENANTID") + else None + ) + if not app_tenantid: + raise Exception( + "Property 'APP_TENANTID' is expected in configuration object" + ) + + self._inner = ManagedIdentityServiceClientCredentialsFactory( + app_id, logger=logger + ) - if app_type == "SingleTenant": + elif app_type == "singletenant": app_tenantid = ( configuration.APP_TENANTID if hasattr(configuration, "APP_TENANTID") @@ -45,4 +65,36 @@ def __init__(self, configuration: Any, *, logger: Logger = None) -> None: "Property 'APP_TENANTID' is expected in configuration object" ) - super().__init__(app_id, app_password, app_tenantid, logger=logger) + self._inner = PasswordServiceClientCredentialFactory( + app_id, app_password, app_tenantid, logger=logger + ) + + # Default to MultiTenant + else: + if not app_id: + raise Exception("Property 'APP_ID' is expected in configuration object") + if not app_password: + raise Exception( + "Property 'APP_PASSWORD' is expected in configuration object" + ) + + self._inner = PasswordServiceClientCredentialFactory( + app_id, app_password, None, logger=logger + ) + + async def is_valid_app_id(self, app_id: str) -> bool: + return await self._inner.is_valid_app_id(app_id) + + async def is_authentication_disabled(self) -> bool: + return await self._inner.is_authentication_disabled() + + async def create_credentials( + self, + app_id: str, + oauth_scope: str, + login_endpoint: str, + validate_authority: bool, + ) -> Authentication: + return await self._inner.create_credentials( + app_id, oauth_scope, login_endpoint, validate_authority + ) diff --git a/libraries/botbuilder-integration-aiohttp/requirements.txt b/libraries/botbuilder-integration-aiohttp/requirements.txt index 1a1057e11..9ce978580 100644 --- a/libraries/botbuilder-integration-aiohttp/requirements.txt +++ b/libraries/botbuilder-integration-aiohttp/requirements.txt @@ -1,4 +1,4 @@ msrest== 0.7.* -botframework-connector==4.16.0 -botbuilder-schema==4.16.0 +botframework-connector==4.17.0 +botbuilder-schema==4.17.0 aiohttp==3.9.5 diff --git a/libraries/botbuilder-integration-aiohttp/setup.py b/libraries/botbuilder-integration-aiohttp/setup.py index b8d84a9aa..891647bb7 100644 --- a/libraries/botbuilder-integration-aiohttp/setup.py +++ b/libraries/botbuilder-integration-aiohttp/setup.py @@ -4,11 +4,11 @@ import os from setuptools import setup -VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" +VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" REQUIRES = [ - "botbuilder-schema==4.16.0", - "botframework-connector==4.16.0", - "botbuilder-core==4.16.0", + "botbuilder-schema==4.17.0", + "botframework-connector==4.17.0", + "botbuilder-core==4.17.0", "yarl>=1.8.1", "aiohttp==3.9.5", ] diff --git a/libraries/botbuilder-integration-applicationinsights-aiohttp/botbuilder/integration/applicationinsights/aiohttp/about.py b/libraries/botbuilder-integration-applicationinsights-aiohttp/botbuilder/integration/applicationinsights/aiohttp/about.py index ab88a6efe..cfaca1e0f 100644 --- a/libraries/botbuilder-integration-applicationinsights-aiohttp/botbuilder/integration/applicationinsights/aiohttp/about.py +++ b/libraries/botbuilder-integration-applicationinsights-aiohttp/botbuilder/integration/applicationinsights/aiohttp/about.py @@ -6,7 +6,7 @@ __title__ = "botbuilder-integration-applicationinsights-aiohttp" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-integration-applicationinsights-aiohttp/setup.py b/libraries/botbuilder-integration-applicationinsights-aiohttp/setup.py index 0a465eaf1..d40487403 100644 --- a/libraries/botbuilder-integration-applicationinsights-aiohttp/setup.py +++ b/libraries/botbuilder-integration-applicationinsights-aiohttp/setup.py @@ -7,10 +7,10 @@ REQUIRES = [ "applicationinsights>=0.11.9", "aiohttp==3.9.5", - "botbuilder-schema==4.16.0", - "botframework-connector==4.16.0", - "botbuilder-core==4.16.0", - "botbuilder-applicationinsights==4.16.0", + "botbuilder-schema==4.17.0", + "botframework-connector==4.17.0", + "botbuilder-core==4.17.0", + "botbuilder-applicationinsights==4.17.0", ] TESTS_REQUIRES = [ "aiounittest==1.3.0", diff --git a/libraries/botbuilder-schema/setup.py b/libraries/botbuilder-schema/setup.py index dba58aa60..2075a5f20 100644 --- a/libraries/botbuilder-schema/setup.py +++ b/libraries/botbuilder-schema/setup.py @@ -5,7 +5,7 @@ from setuptools import setup NAME = "botbuilder-schema" -VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" +VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" REQUIRES = ["msrest== 0.7.*", "urllib3<2.0.0"] root = os.path.abspath(os.path.dirname(__file__)) diff --git a/libraries/botbuilder-testing/botbuilder/testing/about.py b/libraries/botbuilder-testing/botbuilder/testing/about.py index 89af35e45..dca57a9fa 100644 --- a/libraries/botbuilder-testing/botbuilder/testing/about.py +++ b/libraries/botbuilder-testing/botbuilder/testing/about.py @@ -6,7 +6,7 @@ __title__ = "botbuilder-testing" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botbuilder-testing/requirements.txt b/libraries/botbuilder-testing/requirements.txt index b19d84f12..7bca77c2c 100644 --- a/libraries/botbuilder-testing/requirements.txt +++ b/libraries/botbuilder-testing/requirements.txt @@ -1,4 +1,4 @@ -botbuilder-schema==4.16.0 -botbuilder-core==4.16.0 -botbuilder-dialogs==4.16.0 +botbuilder-schema==4.17.0 +botbuilder-core==4.17.0 +botbuilder-dialogs==4.17.0 aiounittest==1.4.0 diff --git a/libraries/botbuilder-testing/setup.py b/libraries/botbuilder-testing/setup.py index e7dc81fd7..9fed4e3ac 100644 --- a/libraries/botbuilder-testing/setup.py +++ b/libraries/botbuilder-testing/setup.py @@ -5,10 +5,10 @@ from setuptools import setup REQUIRES = [ - "botbuilder-schema==4.16.0", - "botbuilder-core==4.16.0", - "botbuilder-dialogs==4.16.0", - "botbuilder-azure==4.16.0", + "botbuilder-schema==4.17.0", + "botbuilder-core==4.17.0", + "botbuilder-dialogs==4.17.0", + "botbuilder-azure==4.17.0", "pytest~=7.3.1", ] diff --git a/libraries/botframework-connector/botframework/connector/about.py b/libraries/botframework-connector/botframework/connector/about.py index 9f11a65e3..7bda53edb 100644 --- a/libraries/botframework-connector/botframework/connector/about.py +++ b/libraries/botframework-connector/botframework/connector/about.py @@ -5,7 +5,7 @@ __title__ = "botframework-connector" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botframework-connector/botframework/connector/auth/__init__.py b/libraries/botframework-connector/botframework/connector/auth/__init__.py index fd34db01a..8747a03c8 100644 --- a/libraries/botframework-connector/botframework/connector/auth/__init__.py +++ b/libraries/botframework-connector/botframework/connector/auth/__init__.py @@ -27,3 +27,5 @@ from .service_client_credentials_factory import * from .user_token_client import * from .authentication_configuration import * +from .managedidentity_app_credentials import * +from .managedidentity_service_client_credential_factory import * diff --git a/libraries/botframework-connector/botframework/connector/auth/_parameterized_bot_framework_authentication.py b/libraries/botframework-connector/botframework/connector/auth/_parameterized_bot_framework_authentication.py index 1388094fe..3419c2099 100644 --- a/libraries/botframework-connector/botframework/connector/auth/_parameterized_bot_framework_authentication.py +++ b/libraries/botframework-connector/botframework/connector/auth/_parameterized_bot_framework_authentication.py @@ -473,11 +473,11 @@ async def _government_channel_validation_validate_identity( ): if identity is None: # No valid identity. Not Authorized. - raise PermissionError() + raise PermissionError("Identity missing") if not identity.is_authenticated: # The token is in some way invalid. Not Authorized. - raise PermissionError() + raise PermissionError("Invalid token") # Now check that the AppID in the claim set matches # what we're looking for. Note that in a multi-tenant bot, this value @@ -487,12 +487,12 @@ async def _government_channel_validation_validate_identity( # Look for the "aud" claim, but only if issued from the Bot Framework issuer = identity.get_claim_value(AuthenticationConstants.ISSUER_CLAIM) if issuer != self._to_bot_from_channel_token_issuer: - raise PermissionError() + raise PermissionError("'iss' claim missing") app_id = identity.get_claim_value(AuthenticationConstants.AUDIENCE_CLAIM) if not app_id: # The relevant audience Claim MUST be present. Not Authorized. - raise PermissionError() + raise PermissionError("'aud' claim missing") # The AppId from the claim in the token must match the AppId specified by the developer. # In this case, the token is destined for the app, so we find the app ID in the audience claim. @@ -507,8 +507,8 @@ async def _government_channel_validation_validate_identity( ) if not service_url_claim: # Claim must be present. Not Authorized. - raise PermissionError() + raise PermissionError("'serviceurl' claim missing") if service_url_claim != service_url: # Claim must match. Not Authorized. - raise PermissionError() + raise PermissionError("Invalid 'serviceurl' claim") diff --git a/libraries/botframework-connector/botframework/connector/auth/jwt_token_validation.py b/libraries/botframework-connector/botframework/connector/auth/jwt_token_validation.py index 659559f14..a0e937156 100644 --- a/libraries/botframework-connector/botframework/connector/auth/jwt_token_validation.py +++ b/libraries/botframework-connector/botframework/connector/auth/jwt_token_validation.py @@ -46,7 +46,7 @@ async def authenticate_request( auth_is_disabled = await credentials.is_authentication_disabled() if not auth_is_disabled: # No Auth Header. Auth is required. Request is not authorized. - raise PermissionError("Unauthorized Access. Request is not authorized") + raise PermissionError("Required Authorization token was not supplied") # Check if the activity is for a skill call and is coming from the Emulator. try: diff --git a/libraries/botframework-connector/botframework/connector/auth/managedidentity_app_credentials.py b/libraries/botframework-connector/botframework/connector/auth/managedidentity_app_credentials.py new file mode 100644 index 000000000..568eb19e2 --- /dev/null +++ b/libraries/botframework-connector/botframework/connector/auth/managedidentity_app_credentials.py @@ -0,0 +1,56 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from abc import ABC + +import msal +import requests + +from .app_credentials import AppCredentials +from .microsoft_app_credentials import MicrosoftAppCredentials + + +class ManagedIdentityAppCredentials(AppCredentials, ABC): + """ + AppCredentials implementation using application ID and password. + """ + + global_token_cache = msal.TokenCache() + + def __init__(self, app_id: str, oauth_scope: str = None): + # super will set proper scope and endpoint. + super().__init__( + app_id=app_id, + oauth_scope=oauth_scope, + ) + + self._managed_identity = {"ManagedIdentityIdType": "ClientId", "Id": app_id} + + self.app = None + + @staticmethod + def empty(): + return MicrosoftAppCredentials("", "") + + def get_access_token(self, force_refresh: bool = False) -> str: + """ + Implementation of AppCredentials.get_token. + :return: The access token for the given app id and password. + """ + + # Firstly, looks up a token from cache + # Since we are looking for token for the current app, NOT for an end user, + # notice we give account parameter as None. + auth_token = self.__get_msal_app().acquire_token_for_client( + resource=self.oauth_scope + ) + return auth_token["access_token"] + + def __get_msal_app(self): + if not self.app: + self.app = msal.ManagedIdentityClient( + self._managed_identity, + http_client=requests.Session(), + token_cache=ManagedIdentityAppCredentials.global_token_cache, + ) + return self.app diff --git a/libraries/botframework-connector/botframework/connector/auth/managedidentity_service_client_credential_factory.py b/libraries/botframework-connector/botframework/connector/auth/managedidentity_service_client_credential_factory.py new file mode 100644 index 000000000..61bf2a12b --- /dev/null +++ b/libraries/botframework-connector/botframework/connector/auth/managedidentity_service_client_credential_factory.py @@ -0,0 +1,39 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from logging import Logger + +from msrest.authentication import Authentication + +from .managedidentity_app_credentials import ManagedIdentityAppCredentials +from .microsoft_app_credentials import MicrosoftAppCredentials +from .service_client_credentials_factory import ServiceClientCredentialsFactory + + +class ManagedIdentityServiceClientCredentialsFactory(ServiceClientCredentialsFactory): + def __init__(self, app_id: str = None, *, logger: Logger = None) -> None: + self.app_id = app_id + self._logger = logger + + async def is_valid_app_id(self, app_id: str) -> bool: + return app_id == self.app_id + + async def is_authentication_disabled(self) -> bool: + return not self.app_id + + async def create_credentials( + self, + app_id: str, + oauth_scope: str, + login_endpoint: str, + validate_authority: bool, + ) -> Authentication: + if await self.is_authentication_disabled(): + return MicrosoftAppCredentials.empty() + + if not await self.is_valid_app_id(app_id): + raise Exception("Invalid app_id") + + credentials = ManagedIdentityAppCredentials(app_id, oauth_scope) + + return credentials diff --git a/libraries/botframework-connector/requirements.txt b/libraries/botframework-connector/requirements.txt index a762e8813..0632606a7 100644 --- a/libraries/botframework-connector/requirements.txt +++ b/libraries/botframework-connector/requirements.txt @@ -1,6 +1,6 @@ msrest==0.7.* -botbuilder-schema==4.16.0 +botbuilder-schema==4.17.0 requests==2.32.0 PyJWT==2.4.0 cryptography==42.0.4 -msal==1.* +msal>=1.29.0 diff --git a/libraries/botframework-connector/setup.py b/libraries/botframework-connector/setup.py index ca4b72025..8a99b3e19 100644 --- a/libraries/botframework-connector/setup.py +++ b/libraries/botframework-connector/setup.py @@ -5,13 +5,13 @@ from setuptools import setup NAME = "botframework-connector" -VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" +VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" REQUIRES = [ "msrest==0.7.*", # "requests>=2.23.0,<2.26", "PyJWT>=2.4.0", - "botbuilder-schema==4.16.0", - "msal==1.*", + "botbuilder-schema==4.17.0", + "msal>=1.29.0", ] root = os.path.abspath(os.path.dirname(__file__)) diff --git a/libraries/botframework-streaming/botframework/streaming/about.py b/libraries/botframework-streaming/botframework/streaming/about.py index 9e4ba1d54..834a4a9a6 100644 --- a/libraries/botframework-streaming/botframework/streaming/about.py +++ b/libraries/botframework-streaming/botframework/streaming/about.py @@ -5,7 +5,7 @@ __title__ = "botframework-streaming" __version__ = ( - os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" + os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" ) __uri__ = "https://www.github.com/Microsoft/botbuilder-python" __author__ = "Microsoft" diff --git a/libraries/botframework-streaming/requirements.txt b/libraries/botframework-streaming/requirements.txt index db9a49e2b..d951e779a 100644 --- a/libraries/botframework-streaming/requirements.txt +++ b/libraries/botframework-streaming/requirements.txt @@ -1,3 +1,3 @@ msrest==0.7.* -botframework-connector>=4.16.0 -botbuilder-schema>=4.16.0 \ No newline at end of file +botframework-connector>=4.17.0 +botbuilder-schema>=4.17.0 \ No newline at end of file diff --git a/libraries/botframework-streaming/setup.py b/libraries/botframework-streaming/setup.py index 0a45151fc..76c1e9549 100644 --- a/libraries/botframework-streaming/setup.py +++ b/libraries/botframework-streaming/setup.py @@ -4,10 +4,10 @@ import os from setuptools import setup -VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.16.0" +VERSION = os.environ["packageVersion"] if "packageVersion" in os.environ else "4.17.0" REQUIRES = [ - "botbuilder-schema==4.16.0", - "botframework-connector==4.16.0", + "botbuilder-schema==4.17.0", + "botframework-connector==4.17.0", ] root = os.path.abspath(os.path.dirname(__file__))