async def _recognize_token(self,
                               context: TurnContext) -> PromptRecognizerResult:
        token = None
        if OAuthPrompt._is_token_response_event(context):
            token = context.activity.value
        elif OAuthPrompt._is_teams_verification_invoke(context):
            code = context.activity.value["state"]
            try:
                token = await self.get_user_token(context, code)
                if token is not None:
                    await context.send_activity(
                        Activity(type="invokeResponse",
                                 value=InvokeResponse(200)))
                else:
                    await context.send_activity(
                        Activity(type="invokeResponse",
                                 value=InvokeResponse(404)))
            except Exception:
                context.send_activity(
                    Activity(type="invokeResponse", value=InvokeResponse(500)))
        elif context.activity.type == ActivityTypes.message and context.activity.text:
            match = re.match(r"(?<!\d)\d{6}(?!\d)", context.activity.text)
            if match:
                token = await self.get_user_token(context, match[0])

        return (PromptRecognizerResult(True, token)
                if token is not None else PromptRecognizerResult())
示例#2
0
 async def post_return():
     nonlocal sequence
     if sequence == 0:
         result = InvokeResponse(body=first_response, status=HTTPStatus.OK)
     else:
         result = InvokeResponse(status=HTTPStatus.CONFLICT)
     sequence += 1
     return result
    async def post_activity(
        self,
        from_bot_id: str,
        to_bot_id: str,
        to_url: str,
        service_url: str,
        conversation_id: str,
        activity: Activity,
    ) -> InvokeResponse:
        app_credentials = await self._get_app_credentials(
            from_bot_id, to_bot_id)

        if not app_credentials:
            raise KeyError(
                "Unable to get appCredentials to connect to the skill")

        # Get token for the skill call
        token = (app_credentials.get_access_token()
                 if app_credentials.microsoft_app_id else None)

        # Capture current activity settings before changing them.
        original_conversation_id = activity.conversation.id
        original_service_url = activity.service_url
        original_relates_to = activity.relates_to
        original_recipient = activity.recipient

        try:
            activity.relates_to = ConversationReference(
                service_url=activity.service_url,
                activity_id=activity.id,
                channel_id=activity.channel_id,
                conversation=ConversationAccount(
                    id=activity.conversation.id,
                    name=activity.conversation.name,
                    conversation_type=activity.conversation.conversation_type,
                    aad_object_id=activity.conversation.aad_object_id,
                    is_group=activity.conversation.is_group,
                    role=activity.conversation.role,
                    tenant_id=activity.conversation.tenant_id,
                    properties=activity.conversation.properties,
                ),
                bot=None,
            )
            activity.conversation.id = conversation_id
            activity.service_url = service_url
            if not activity.recipient:
                activity.recipient = ChannelAccount(role=RoleTypes.skill)
            else:
                activity.recipient.role = RoleTypes.skill

            status, content = await self._post_content(to_url, token, activity)

            return InvokeResponse(status=status, body=content)

        finally:
            # Restore activity properties.
            activity.conversation.id = original_conversation_id
            activity.service_url = original_service_url
            activity.relates_to = original_relates_to
            activity.recipient = original_recipient
示例#4
0
    async def post_activity(
        self,
        from_bot_id: str,
        to_bot_id: str,
        to_url: str,
        service_url: str,
        conversation_id: str,
        activity: Activity,
    ) -> InvokeResponse:
        app_credentials = await self._get_app_credentials(
            from_bot_id, to_bot_id)

        if not app_credentials:
            raise KeyError(
                "Unable to get appCredentials to connect to the skill")

        # Get token for the skill call
        token = (app_credentials.get_access_token()
                 if app_credentials.microsoft_app_id else None)

        # Capture current activity settings before changing them.
        # TODO: DO we need to set the activity ID? (events that are created manually don't have it).
        original_conversation_id = activity.conversation.id
        original_service_url = activity.service_url
        original_caller_id = activity.caller_id

        try:
            activity.conversation.id = conversation_id
            activity.service_url = service_url
            activity.caller_id = from_bot_id

            headers_dict = {
                "Content-type": "application/json; charset=utf-8",
            }
            if token:
                headers_dict.update({
                    "Authorization": f"Bearer {token}",
                })

            json_content = json.dumps(activity.serialize())
            resp = await self._session.post(
                to_url,
                data=json_content.encode("utf-8"),
                headers=headers_dict,
            )
            resp.raise_for_status()
            data = (await resp.read()).decode()
            content = json.loads(data) if data else None

            if content:
                return InvokeResponse(status=resp.status_code, body=content)

        finally:
            # Restore activity properties.
            activity.conversation.id = original_conversation_id
            activity.service_url = original_service_url
            activity.caller_id = original_caller_id
 async def _send_invoke_response(
     self,
     turn_context: TurnContext,
     body: object = None,
     http_status_code=HTTPStatus.OK,
 ):
     await turn_context.send_activity(
         Activity(
             type=ActivityTypes.invoke_response,
             value=InvokeResponse(status=http_status_code, body=body),
         )
     )
示例#6
0
 def _get_token_exchange_invoke_response(
     self, status: int, failure_detail: str, identifier: str = None
 ) -> Activity:
     return Activity(
         type=ActivityTypes.invoke_response,
         value=InvokeResponse(
             status=status,
             body=TokenExchangeInvokeResponse(
                 id=identifier,
                 connection_name=self._settings.connection_name,
                 failure_detail=failure_detail,
             ),
         ),
     )
示例#7
0
 async def mock_post_activity(
     from_bot_id: str,
     to_bot_id: str,
     to_url: str,
     service_url: str,
     conversation_id: str,
     activity: Activity,
 ):
     nonlocal callback, return_status
     if callback:
         await callback(
             from_bot_id,
             to_bot_id,
             to_url,
             service_url,
             conversation_id,
             activity,
         )
     return InvokeResponse(status=return_status)
示例#8
0
    async def process_streaming_activity(
        self,
        activity: Activity,
        bot_callback_handler: Callable[[TurnContext], Awaitable],
    ) -> InvokeResponse:
        if not activity:
            raise TypeError(
                f"'activity: {activity.__class__.__name__}' argument can't be None"
            )
        """
        If a conversation has moved from one connection to another for the same Channel or Skill and
        hasn't been forgotten by the previous StreamingRequestHandler. The last requestHandler
        the conversation has been associated with should always be the active connection.
        """
        request_handler = [
            handler for handler in self.request_handlers
            if handler.service_url == activity.service_url
            and handler.has_conversation(activity.conversation.id)
        ]
        request_handler = request_handler[-1] if request_handler else None
        context = TurnContext(self, activity)

        if self.claims_identity:
            context.turn_state[self.BOT_IDENTITY_KEY] = self.claims_identity

        connector_client = self._create_streaming_connector_client(
            activity, request_handler)
        context.turn_state[self.BOT_CONNECTOR_CLIENT_KEY] = connector_client

        await self.run_pipeline(context, bot_callback_handler)

        if activity.type == ActivityTypes.invoke:
            activity_invoke_response = context.turn_state.get(
                self._INVOKE_RESPONSE_KEY)

            if not activity_invoke_response:
                return InvokeResponse(status=HTTPStatus.NOT_IMPLEMENTED)
            return activity_invoke_response.value

        return None
示例#9
0
        async def mock_post_activity(
            from_bot_id: str,
            to_bot_id: str,
            to_url: str,
            service_url: str,
            conversation_id: str,
            activity: Activity,
        ):
            nonlocal callback, return_status
            if callback:
                await callback(
                    from_bot_id,
                    to_bot_id,
                    to_url,
                    service_url,
                    conversation_id,
                    activity,
                )

            if isinstance(return_status, Callable):
                return await return_status()
            return InvokeResponse(status=return_status, body=activity_list)
    async def _recognize_token(
            self, dialog_context: DialogContext) -> PromptRecognizerResult:
        context = dialog_context.context
        token = None
        if OAuthPrompt._is_token_response_event(context):
            token = context.activity.value

            # fixup the turnContext's state context if this was received from a skill host caller
            state: CallerInfo = dialog_context.active_dialog.state[
                OAuthPrompt.PERSISTED_CALLER]
            if state:
                # set the ServiceUrl to the skill host's Url
                dialog_context.context.activity.service_url = state.caller_service_url

                # recreate a ConnectorClient and set it in TurnState so replies use the correct one
                if not isinstance(context.adapter, ConnectorClientBuilder):
                    raise TypeError(
                        "OAuthPrompt: IConnectorClientProvider interface not implemented by the current adapter"
                    )

                connector_client_builder: ConnectorClientBuilder = context.adapter
                claims_identity = context.turn_state.get(
                    BotAdapter.BOT_IDENTITY_KEY)
                connector_client = await connector_client_builder.create_connector_client(
                    dialog_context.context.activity.service_url,
                    claims_identity,
                    state.scope,
                )

                context.turn_state[
                    BotAdapter.BOT_CONNECTOR_CLIENT_KEY] = connector_client

        elif OAuthPrompt._is_teams_verification_invoke(context):
            code = context.activity.value["state"]
            try:
                token = await self.get_user_token(context, code)
                if token is not None:
                    await context.send_activity(
                        Activity(
                            type="invokeResponse",
                            value=InvokeResponse(int(HTTPStatus.OK)),
                        ))
                else:
                    await context.send_activity(
                        Activity(
                            type="invokeResponse",
                            value=InvokeResponse(int(HTTPStatus.NOT_FOUND)),
                        ))
            except Exception:
                await context.send_activity(
                    Activity(
                        type="invokeResponse",
                        value=InvokeResponse(
                            int(HTTPStatus.INTERNAL_SERVER_ERROR)),
                    ))
        elif self._is_token_exchange_request_invoke(context):
            if isinstance(context.activity.value, dict):
                context.activity.value = TokenExchangeInvokeRequest(
                ).from_dict(context.activity.value)

            if not (context.activity.value and self._is_token_exchange_request(
                    context.activity.value)):
                # Received activity is not a token exchange request.
                await context.send_activity(
                    self._get_token_exchange_invoke_response(
                        int(HTTPStatus.BAD_REQUEST),
                        "The bot received an InvokeActivity that is missing a TokenExchangeInvokeRequest value."
                        " This is required to be sent with the InvokeActivity.",
                    ))
            elif (context.activity.value.connection_name !=
                  self._settings.connection_name):
                # Connection name on activity does not match that of setting.
                await context.send_activity(
                    self._get_token_exchange_invoke_response(
                        int(HTTPStatus.BAD_REQUEST),
                        "The bot received an InvokeActivity with a TokenExchangeInvokeRequest containing a"
                        " ConnectionName that does not match the ConnectionName expected by the bots active"
                        " OAuthPrompt. Ensure these names match when sending the InvokeActivityInvalid"
                        " ConnectionName in the TokenExchangeInvokeRequest",
                    ))
            elif not getattr(context.adapter, "exchange_token"):
                # Token Exchange not supported in the adapter.
                await context.send_activity(
                    self._get_token_exchange_invoke_response(
                        int(HTTPStatus.BAD_GATEWAY),
                        "The bot's BotAdapter does not support token exchange operations."
                        " Ensure the bot's Adapter supports the ExtendedUserTokenProvider interface.",
                    ))

                raise AttributeError(
                    "OAuthPrompt._recognize_token(): not supported by the current adapter."
                )
            else:
                # No errors. Proceed with token exchange.
                extended_user_token_provider: ExtendedUserTokenProvider = context.adapter

                token_exchange_response = None
                try:
                    token_exchange_response = await extended_user_token_provider.exchange_token_from_credentials(
                        context,
                        self._settings.oath_app_credentials,
                        self._settings.connection_name,
                        context.activity.from_property.id,
                        TokenExchangeRequest(
                            token=context.activity.value.token),
                    )
                except:
                    # Ignore Exceptions
                    # If token exchange failed for any reason, tokenExchangeResponse above stays null, and
                    # hence we send back a failure invoke response to the caller.
                    pass

                if not token_exchange_response or not token_exchange_response.token:
                    await context.send_activity(
                        self._get_token_exchange_invoke_response(
                            int(HTTPStatus.PRECONDITION_FAILED),
                            "The bot is unable to exchange token. Proceed with regular login.",
                        ))
                else:
                    await context.send_activity(
                        self._get_token_exchange_invoke_response(
                            int(HTTPStatus.OK), None,
                            context.activity.value.id))
                    token = TokenResponse(
                        channel_id=token_exchange_response.channel_id,
                        connection_name=token_exchange_response.
                        connection_name,
                        token=token_exchange_response.token,
                        expiration=None,
                    )
        elif context.activity.type == ActivityTypes.message and context.activity.text:
            match = re.match(r"(?<!\d)\d{6}(?!\d)", context.activity.text)
            if match:
                token = await self.get_user_token(context, match[0])

        return (PromptRecognizerResult(True, token)
                if token is not None else PromptRecognizerResult())
 def create_invoke_response(self) -> InvokeResponse:
     return InvokeResponse(status=int(self._status_code), body=self._body)
 def _create_invoke_response(body: object = None) -> InvokeResponse:
     return InvokeResponse(status=int(HTTPStatus.OK), body=body)
示例#13
0
    async def post_activity(
        self,
        from_bot_id: str,
        to_bot_id: str,
        to_url: str,
        service_url: str,
        conversation_id: str,
        activity: Activity,
    ) -> InvokeResponse:
        app_credentials = await self._get_app_credentials(
            from_bot_id, to_bot_id)

        if not app_credentials:
            raise KeyError(
                "Unable to get appCredentials to connect to the skill")

        # Get token for the skill call
        token = (app_credentials.get_access_token()
                 if app_credentials.microsoft_app_id else None)

        # Capture current activity settings before changing them.
        # TODO: DO we need to set the activity ID? (events that are created manually don't have it).
        original_conversation_id = activity.conversation.id
        original_service_url = activity.service_url
        original_caller_id = activity.caller_id
        original_relates_to = activity.relates_to

        try:
            # TODO: The relato has to be ported to the adapter in the new integration library when
            #  resolving conflicts in merge
            activity.relates_to = ConversationReference(
                service_url=activity.service_url,
                activity_id=activity.id,
                channel_id=activity.channel_id,
                conversation=ConversationAccount(
                    id=activity.conversation.id,
                    name=activity.conversation.name,
                    conversation_type=activity.conversation.conversation_type,
                    aad_object_id=activity.conversation.aad_object_id,
                    is_group=activity.conversation.is_group,
                    role=activity.conversation.role,
                    tenant_id=activity.conversation.tenant_id,
                    properties=activity.conversation.properties,
                ),
                bot=None,
            )
            activity.conversation.id = conversation_id
            activity.service_url = service_url
            activity.caller_id = f"urn:botframework:aadappid:{from_bot_id}"

            headers_dict = {
                "Content-type": "application/json; charset=utf-8",
            }
            if token:
                headers_dict.update({
                    "Authorization": f"Bearer {token}",
                })

            json_content = json.dumps(activity.serialize())
            resp = await self._session.post(
                to_url,
                data=json_content.encode("utf-8"),
                headers=headers_dict,
            )
            resp.raise_for_status()
            data = (await resp.read()).decode()
            content = json.loads(data) if data else None

            return InvokeResponse(status=resp.status, body=content)

        finally:
            # Restore activity properties.
            activity.conversation.id = original_conversation_id
            activity.service_url = original_service_url
            activity.caller_id = original_caller_id
            activity.relates_to = original_relates_to
 def _create_invoke_response(body: object = None) -> InvokeResponse:
     return InvokeResponse(status=int(HTTPStatus.OK),
                           body=serializer_helper(body))
示例#15
0
    async def _recognize_token(self,
                               context: TurnContext) -> PromptRecognizerResult:
        token = None
        if OAuthPrompt._is_token_response_event(context):
            token = context.activity.value
        elif OAuthPrompt._is_teams_verification_invoke(context):
            code = context.activity.value["state"]
            try:
                token = await self.get_user_token(context, code)
                if token is not None:
                    await context.send_activity(
                        Activity(
                            type="invokeResponse",
                            value=InvokeResponse(int(HTTPStatus.OK)),
                        ))
                else:
                    await context.send_activity(
                        Activity(
                            type="invokeResponse",
                            value=InvokeResponse(int(HTTPStatus.NOT_FOUND)),
                        ))
            except Exception:
                await context.send_activity(
                    Activity(
                        type="invokeResponse",
                        value=InvokeResponse(
                            int(HTTPStatus.INTERNAL_SERVER_ERROR)),
                    ))
        elif self._is_token_exchange_request_invoke(context):
            if isinstance(context.activity.value, dict):
                context.activity.value = TokenExchangeInvokeRequest(
                ).from_dict(context.activity.value)

            if not (context.activity.value and self._is_token_exchange_request(
                    context.activity.value)):
                # Received activity is not a token exchange request.
                await context.send_activity(
                    self._get_token_exchange_invoke_response(
                        int(HTTPStatus.BAD_REQUEST),
                        "The bot received an InvokeActivity that is missing a TokenExchangeInvokeRequest value."
                        " This is required to be sent with the InvokeActivity.",
                    ))
            elif (context.activity.value.connection_name !=
                  self._settings.connection_name):
                # Connection name on activity does not match that of setting.
                await context.send_activity(
                    self._get_token_exchange_invoke_response(
                        int(HTTPStatus.BAD_REQUEST),
                        "The bot received an InvokeActivity with a TokenExchangeInvokeRequest containing a"
                        " ConnectionName that does not match the ConnectionName expected by the bots active"
                        " OAuthPrompt. Ensure these names match when sending the InvokeActivityInvalid"
                        " ConnectionName in the TokenExchangeInvokeRequest",
                    ))
            elif not getattr(context.adapter, "exchange_token"):
                # Token Exchange not supported in the adapter.
                await context.send_activity(
                    self._get_token_exchange_invoke_response(
                        int(HTTPStatus.BAD_GATEWAY),
                        "The bot's BotAdapter does not support token exchange operations."
                        " Ensure the bot's Adapter supports the ITokenExchangeProvider interface.",
                    ))

                raise AttributeError(
                    "OAuthPrompt.recognize(): not supported by the current adapter."
                )
            else:
                # No errors. Proceed with token exchange.
                extended_user_token_provider: ExtendedUserTokenProvider = context.adapter
                token_exchange_response = await extended_user_token_provider.exchange_token_from_credentials(
                    context,
                    self._settings.oath_app_credentials,
                    self._settings.connection_name,
                    context.activity.from_property.id,
                    TokenExchangeRequest(token=context.activity.value.token),
                )

                if not token_exchange_response or not token_exchange_response.token:
                    await context.send_activity(
                        self._get_token_exchange_invoke_response(
                            int(HTTPStatus.CONFLICT),
                            "The bot is unable to exchange token. Proceed with regular login.",
                        ))
                else:
                    await context.send_activity(
                        self._get_token_exchange_invoke_response(
                            int(HTTPStatus.OK), None,
                            context.activity.value.id))
                    token = TokenResponse(
                        channel_id=token_exchange_response.channel_id,
                        connection_name=token_exchange_response.
                        connection_name,
                        token=token_exchange_response.token,
                        expiration=None,
                    )
        elif context.activity.type == ActivityTypes.message and context.activity.text:
            match = re.match(r"(?<!\d)\d{6}(?!\d)", context.activity.text)
            if match:
                token = await self.get_user_token(context, match[0])

        return (PromptRecognizerResult(True, token)
                if token is not None else PromptRecognizerResult())