async def _intercept_oauth_cards(
        self,
        activities: List[Activity],
        turn_context: TurnContext,
    ) -> bool:
        if not activities:
            return False
        activity = activities[0]

        if activity.attachments:
            for attachment in filter(lambda att: att.content_type == CardFactory.content_types.oauth_card,
                                     activity.attachments):
                oauth_card: OAuthCard = OAuthCard().from_dict(attachment.content)
                oauth_card.token_exchange_resource: TokenExchangeResource = TokenExchangeResource().from_dict(
                    oauth_card.token_exchange_resource)
                if oauth_card.token_exchange_resource:
                    token_exchange_provider: BotFrameworkAdapter = turn_context.adapter

                    result = await token_exchange_provider.exchange_token(
                        turn_context,
                        self._connection_name,
                        turn_context.activity.from_property.id,
                        TokenExchangeRequest(uri=oauth_card.token_exchange_resource.uri)
                    )

                    if result.token:
                        return await self._send_token_exchange_invoke_to_skill(
                            turn_context,
                            activity,
                            oauth_card.token_exchange_resource.id,
                            result.token
                        )
        return False
Exemplo n.º 2
0
    async def _intercept_oauth_cards(self, claims_identity: ClaimsIdentity,
                                     activity: Activity) -> bool:
        if activity.attachments:
            oauth_card_attachment = next(
                (attachment for attachment in activity.attachments
                 if attachment.content_type == ContentTypes.oauth_card),
                None,
            )

            if oauth_card_attachment:
                target_skill = self._get_calling_skill(claims_identity)
                if target_skill:
                    oauth_card = oauth_card_attachment.content
                    token_exchange_resource = oauth_card.get(
                        "TokenExchangeResource") or oauth_card.get(
                            "tokenExchangeResource")
                    if token_exchange_resource:
                        context = TurnContext(self._adapter, activity)
                        context.turn_state["BotIdentity"] = claims_identity

                        # We need to know what connection name to use for the token exchange so we figure that out here
                        connection_name = (
                            self._configuration.SSO_CONNECTION_NAME
                            if target_skill.group == "Waterfall" else
                            self._configuration.SSO_CONNECTION_NAME_TEAMS)

                        if not connection_name:
                            raise ValueError(
                                "The SSO connection name cannot be null.")

                        # AAD token exchange
                        try:
                            uri = token_exchange_resource.get("uri")
                            result = await self._token_exchange_provider.exchange_token(
                                context,
                                connection_name,
                                activity.recipient.id,
                                TokenExchangeRequest(uri=uri),
                            )

                            if result.token:
                                # If token above is null, then SSO has failed and hence we return false.
                                # If not, send an invoke to the skill with the token.
                                return await self._send_token_exchange_invoke_to_skill(
                                    incoming_activity=activity,
                                    connection_name=oauth_card.get(
                                        "connectionName"),
                                    resource_id=token_exchange_resource.get(
                                        "id"),
                                    token=result.token,
                                    target_skill=target_skill,
                                )

                        except Exception as exception:
                            print(f"Unable to exchange token: {exception}")
                            traceback.print_exc()
                            return False

        return False
Exemplo n.º 3
0
    async def _intercept_oauth_cards(
        self, context: TurnContext, activity: Activity, connection_name: str
    ):
        """
        Tells is if we should intercept the OAuthCard message.
        """
        if not connection_name or not isinstance(
            context.adapter, ExtendedUserTokenProvider
        ):
            # The adapter may choose not to support token exchange, in which case we fallback to
            # showing an oauth card to the user.
            return False

        oauth_card_attachment = next(
            attachment
            for attachment in activity.attachments
            if attachment.content_type == ContentTypes.oauth_card
        )
        if oauth_card_attachment:
            oauth_card = oauth_card_attachment.content
            if (
                oauth_card
                and oauth_card.token_exchange_resource
                and oauth_card.token_exchange_resource.uri
            ):
                try:
                    result = await context.adapter.exchange_token(
                        turn_context=context,
                        connection_name=connection_name,
                        user_id=context.activity.from_property.id,
                        exchange_request=TokenExchangeRequest(
                            uri=oauth_card.token_exchange_resource.uri
                        ),
                    )

                    if result and result.token:
                        # If token above is null, then SSO has failed and hence we return false.
                        # If not, send an invoke to the skill with the token.
                        return await self._send_token_exchange_invoke_to_skill(
                            activity,
                            oauth_card.token_exchange_resource.id,
                            oauth_card.connection_name,
                            result.token,
                        )
                except:
                    # Failures in token exchange are not fatal. They simply mean that the user needs
                    # to be shown the OAuth card.
                    return False

        return False
    async def _exchanged_token(self, turn_context: TurnContext) -> bool:
        token_exchange_response: TokenResponse = None
        aux_dict = {}
        if turn_context.activity.value:
            for prop in ["id", "connection_name", "token", "properties"]:
                aux_dict[prop] = turn_context.activity.value.get(prop)
        token_exchange_request = TokenExchangeInvokeRequest(
            id=aux_dict["id"],
            connection_name=aux_dict["connection_name"],
            token=aux_dict["token"],
            properties=aux_dict["properties"],
        )
        try:
            adapter = turn_context.adapter
            if isinstance(turn_context.adapter, ExtendedUserTokenProvider):
                token_exchange_response = await adapter.exchange_token(
                    turn_context,
                    self._oauth_connection_name,
                    turn_context.activity.from_property.id,
                    TokenExchangeRequest(token=token_exchange_request.token),
                )
            else:
                raise Exception(
                    "Not supported: Token Exchange is not supported by the current adapter."
                )
        except:
            traceback.print_exc()
        if not token_exchange_response or not token_exchange_response.token:
            # The token could not be exchanged (which could be due to a consent requirement)
            # Notify the sender that PreconditionFailed so they can respond accordingly.

            invoke_response = TokenExchangeInvokeResponse(
                id=token_exchange_request.id,
                connection_name=self._oauth_connection_name,
                failure_detail="The bot is unable to exchange token. Proceed with regular login.",
            )

            await self._send_invoke_response(
                turn_context, invoke_response, HTTPStatus.PRECONDITION_FAILED
            )

            return False

        return True
        async def callback(context):
            result = await adapter.exchange_token_from_credentials(
                turn_context=context,
                oauth_app_credentials=None,
                connection_name=context.activity.value.connection_name,
                exchange_request=TokenExchangeRequest(
                    token=context.activity.value.token, uri=context.activity.service_url
                ),
                user_id="user_id",
            )

            activity = Activity(
                type=ActivityTypes.invoke_response,
                value=InvokeResponse(
                    status=200,
                    body=TokenExchangeInvokeResponse(
                        id=context.activity.value.id,
                        connection_name=result.connection_name,
                    ),
                ),
            )

            await context.send_activity(activity)