Saltar a contenido

Integración con Microsoft Teams

Se puede añadir una integración con Microsoft Teams a su instalación de Drovio Server. Permite iniciar sesiones de Drovio y unirse a ellas desde Microsoft Teams, por el cuadro de redacción o por comando del bot. Se presenta en forma de un archivo JAR que se añade a Drovio Server y luego se configura. Deberá crear un Azure Bot y una aplicación en Microsoft Entra ID.

Declarar el bot en Azure

La declaración del bot puede hacerse desde el portal de Azure, la Azure CLI o Terraform. Las tres vías llevan al mismo resultado: un registro de aplicación, un secreto de cliente, y un recurso Azure Bot cuyo canal de Teams está activado.

Crear el recurso Azure Bot

En el portal de Azure, elija Create a resource, busque Azure Bot, luego Create.

Campo Valor
Bot handle Un nombre único, por ejemplo Drovio
Subscription La suscripción que se facturará
Resource group Un grupo nuevo, por ejemplo Drovio
Pricing tier Free (F0)
Type of app Single Tenant
Creation type Create new Microsoft App ID

Apuntar el bot hacia su servidor

Abra el recurso, luego Settings y Configuration. Indique en Messaging endpoint:

https://<your server>/msteams/api/messages

Punto de acceso público

La ruta /msteams/api/messages debe ser accesible en HTTPS desde los servidores de Microsoft. Si su Drovio Server está detrás de un cortafuegos o de un proxy inverso, procure abrir esta ruta a Internet.

Aplique, luego vaya a Settings y Channels, y añada Microsoft Teams.

Anotar los tres valores que necesita el plugin

Siempre bajo Settings y Configuration, haga clic en Manage Password junto al Microsoft App ID. Esto abre el registro de aplicación en Microsoft Entra ID.

En el panel Overview, anote:

Valor en Azure Se usa como
Application (client) ID client_id
Directory (tenant) ID tenant_id

Vaya después a Certificates & secrets, pestaña Client secrets, y haga clic en New client secret. Copie enseguida la columna Value: solo se muestra una vez, y hay que generar un nuevo secreto si la deja pasar. Es el client_secret.

Exponer la API y conceder el acceso a Graph

Bajo Expose an API, haga clic en Set junto al Application ID URI, luego en Save.

Bajo API permissions, añada un permiso sobre Microsoft Graph, elija Application permissions, y seleccione los dos permisos enumerados más abajo. Concédales el consentimiento de administrador.

Declarar el URI de redirección

Útil solo si piensa publicar la aplicación desde el panel de administración en lugar de depositarla usted mismo.

Bajo Authentication, Add a platform, elija Web, y añada el URI de redirección:

https://<your server>/admin/access/msteams/publish/callback

Sin él, la publicación falla con AADSTS500113: No reply address is registered for the application. Si el acceso a la administración está restringido por dirección IP en este servidor, la dirección desde la que vuelve el navegador también debe estar autorizada, sin lo cual el retorno se rechaza con un 403.

Sustituya <your server> por la URL pública de su instancia, y elija su propio grupo de recursos y su región.

Aquí la aplicación precede al bot

El portal crea el registro de aplicación y el bot en un solo formulario. La CLI no puede hacerlo: az bot create exige el identificador de aplicación como argumento obligatorio, por lo que el registro debe existir antes. El resultado final es idéntico.

Fije primero los cinco nombres, el resto de los comandos podrá pegarse después tal cual:

Variable Lo que nombra
SERVER La URL pública de su Drovio Server
APP_NAME El nombre para mostrar del registro de aplicación
BOT_NAME El recurso bot, que debe estar libre a escala de Azure
GROUP El grupo de recursos que aloja el bot
LOCATION La región del grupo de recursos
SERVER=https://<your server>
APP_NAME=Drovio
BOT_NAME=Drovio
GROUP=Drovio
LOCATION=westeurope

Cree el registro de aplicación, su service principal, su Application ID URI y su secreto de cliente:

APP_ID=$(az ad app create \
  --display-name "$APP_NAME" \
  --sign-in-audience AzureADMyOrg \
  --web-redirect-uris "$SERVER/admin/access/msteams/publish/callback" \
  --query appId --output tsv)

TENANT_ID=$(az account show --query tenantId --output tsv)

az ad sp create --id "$APP_ID"

az ad app update --id "$APP_ID" --identifier-uris "api://$APP_ID"

CLIENT_SECRET=$(az ad app credential reset --id "$APP_ID" --append \
  --display-name drovio-server --query password --output tsv)

La línea az ad sp create corresponde al paso que el portal le oculta. Crea el service principal al que se conceden los permisos, y sin él el consentimiento de administrador falla. El URI de identificación es aquello a lo que apunta el manifest de Teams. El secreto de cliente solo se muestra una vez, procure conservar lo que captura el último comando.

Solicite los dos permisos de Graph, resueltos por su nombre para que no haya que copiar ningún identificador. El consentimiento vendrá más tarde, al final de esta pestaña:

GRAPH_ID=00000003-0000-0000-c000-000000000000

USER_READ=$(az ad sp show --id $GRAPH_ID \
  --query "appRoles[?value=='User.Read.All'].id | [0]" --output tsv)
CATALOG_READ=$(az ad sp show --id $GRAPH_ID \
  --query "appRoles[?value=='AppCatalog.Read.All'].id | [0]" --output tsv)

az ad app permission add --id "$APP_ID" --api $GRAPH_ID \
  --api-permissions "$USER_READ=Role" "$CATALOG_READ=Role"

Este comando muestra un mensaje que le invita a lanzar az ad app permission grant: ignórelo, ese comando concierne a los permisos delegados, mientras que estos dos son permisos de aplicación.

Luego el recurso bot en sí, y su canal de Teams:

az group create --name "$GROUP" --location "$LOCATION"

az bot create \
  --name "$BOT_NAME" \
  --resource-group "$GROUP" \
  --app-type SingleTenant \
  --appid "$APP_ID" \
  --tenant-id "$TENANT_ID" \
  --endpoint "$SERVER/msteams/api/messages" \
  --sku F0

az bot msteams create --name "$BOT_NAME" --resource-group "$GROUP"

echo "client_id     $APP_ID (Application ID)"
echo "tenant_id     $TENANT_ID (Directory ID)"
echo "client_secret $CLIENT_SECRET"

Conceder el consentimiento en último lugar

El consentimiento es la última etapa, y debe verificarse. Microsoft Entra ID necesita que el registro de aplicación, su service principal y los permisos solicitados se hayan propagado antes de poder actuar sobre ellos. Lanzado demasiado pronto, el comando no señala ningún error y no concede nada:

az ad app permission admin-consent --id "$APP_ID"

SP_ID=$(az ad sp show --id "$APP_ID" --query id --output tsv)
az rest --method GET \
  --url "https://graph.microsoft.com/v1.0/servicePrincipals/$SP_ID/appRoleAssignments" \
  --query "length(value)" --output tsv

El último comando debe mostrar 2. Si muestra 0, espere un minuto y vuelva a ejecutar ambos. Conceder el consentimiento exige el rol Privileged Role Administrator o Global Administrator.

El portal es la alternativa fiable

Si el recuento se mantiene en 0, abra el registro de aplicación en Microsoft Entra ID, vaya a API permissions y haga clic en Grant admin consent for <su tenant>. La columna Status muestra entonces Granted, y el comando anterior muestra 2.

La misma puesta en marcha, para una infraestructura ya descrita en forma de código. Requiere el proveedor azuread en versión 3 o superior, donde aparecieron los pequeños recursos de aplicación componibles. Los archivos de abajo forman un solo módulo raíz.

terraform {
  required_version = ">= 1.0.0, < 2.0.0"

  required_providers {
    azuread = {
      source  = "hashicorp/azuread"
      version = "~> 3.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.0"
    }
  }
}
provider "azurerm" {
  subscription_id = var.subscription_id
  features {}
}
variable "subscription_id" {
  description = "Azure subscription hosting the bot resource"
  type        = string
}

variable "server_url" {
  description = "Public URL of the Drovio Server instance, without a trailing slash"
  type        = string
}
data "azuread_client_config" "current" {}

data "azuread_application_published_app_ids" "well_known" {}

data "azuread_service_principal" "msgraph" {
  client_id = data.azuread_application_published_app_ids.well_known.result["MicrosoftGraph"]
}
resource "azuread_application_registration" "drovio" {
  display_name     = "Drovio"
  sign_in_audience = "AzureADMyOrg"
}

resource "azuread_application_identifier_uri" "drovio" {
  application_id = azuread_application_registration.drovio.id
  identifier_uri = "api://${azuread_application_registration.drovio.client_id}"
}

resource "azuread_application_redirect_uris" "drovio" {
  application_id = azuread_application_registration.drovio.id
  type           = "Web"
  redirect_uris  = ["${var.server_url}/admin/access/msteams/publish/callback"]
}

resource "azuread_application_api_access" "drovio" {
  application_id = azuread_application_registration.drovio.id
  api_client_id  = data.azuread_application_published_app_ids.well_known.result["MicrosoftGraph"]

  role_ids = [
    data.azuread_service_principal.msgraph.app_role_ids["User.Read.All"],
    data.azuread_service_principal.msgraph.app_role_ids["AppCatalog.Read.All"],
  ]
}

resource "azuread_application_password" "drovio" {
  application_id = azuread_application_registration.drovio.id
}

resource "azuread_service_principal" "drovio" {
  client_id = azuread_application_registration.drovio.client_id
}

# The two assignments below are the admin consent
resource "azuread_app_role_assignment" "user_read_all" {
  app_role_id         = data.azuread_service_principal.msgraph.app_role_ids["User.Read.All"]
  principal_object_id = azuread_service_principal.drovio.object_id
  resource_object_id  = data.azuread_service_principal.msgraph.object_id
}

resource "azuread_app_role_assignment" "app_catalog_read_all" {
  app_role_id         = data.azuread_service_principal.msgraph.app_role_ids["AppCatalog.Read.All"]
  principal_object_id = azuread_service_principal.drovio.object_id
  resource_object_id  = data.azuread_service_principal.msgraph.object_id
}

resource "azurerm_resource_group" "drovio" {
  name     = "Drovio"
  location = "West Europe"
}

resource "azurerm_bot_service_azure_bot" "drovio" {
  name                    = "Drovio"
  resource_group_name     = azurerm_resource_group.drovio.name
  location                = "global"
  sku                     = "F0"
  microsoft_app_id        = azuread_application_registration.drovio.client_id
  microsoft_app_type      = "SingleTenant"
  microsoft_app_tenant_id = data.azuread_client_config.current.tenant_id
  endpoint                = "${var.server_url}/msteams/api/messages"
}

resource "azurerm_bot_channel_ms_teams" "drovio" {
  bot_name            = azurerm_bot_service_azure_bot.drovio.name
  location            = azurerm_bot_service_azure_bot.drovio.location
  resource_group_name = azurerm_resource_group.drovio.name
}
output "client_id" {
  description = "Application (client) ID, for the plugin configuration"
  value       = azuread_application_registration.drovio.client_id
}

output "tenant_id" {
  description = "Directory (tenant) ID, for the plugin configuration"
  value       = data.azuread_client_config.current.tenant_id
}

output "client_secret" {
  description = "Client secret, for the plugin configuration"
  value       = azuread_application_password.drovio.value
  sensitive   = true
}

Tres cosas que conviene saber antes de aplicar:

  • El secreto de cliente acaba en el estado de Terraform, que pasa entonces a contener una credencial hacia su tenant y debe protegerse como tal. Retire el recurso azuread_application_password y cree el secreto a mano si eso no resulta aceptable allí donde conserva su estado.
  • Los dos recursos azuread_app_role_assignment hacen lo que realiza Grant admin consent en el portal. La identidad que ejecuta Terraform debe disponer del rol Privileged Role Administrator o Global Administrator para crearlos.
  • azurerm_bot_service_azure_bot es el recurso Azure Bot. No use el antiguo azurerm_bot_channels_registration, que describe la generación anterior de declaración de bot.

Un bot mono-tenant sirve a su propio tenant, que es lo que necesita un despliegue autoalojado. La distribución multi-tenant hacia los tenants de sus clientes es otro asunto, que pasa por AppSource.

Sea cual sea el método elegido, el nombre del bot tiene entre 4 y 42 caracteres y debe estar libre a escala de Azure, de modo que Drovio a secas puede estar ya ocupado. El recurso bot en sí vive en la ubicación global, sea cual sea la región de su grupo de recursos.

El secreto de cliente caduca

El mismo secreto autentica al bot cuando responde en Teams y al plugin cuando llama a Graph. A su caducidad, la aplicación deja de responder y el panel pierde de vista el catálogo, hasta que se introduce un nuevo secreto en el panel de administración. Su duración depende de la forma en que lo haya creado:

Método Duración
Portal A su elección, 24 meses como máximo, y Microsoft aconseja menos de 12
Azure CLI Un año, modificable con --years en az ad app credential reset
Terraform Dos años, el valor por defecto que aplica Microsoft Entra ID cuando se omite end_date_relative

Anote la fecha de caducidad en algún sitio y prevea la rotación: cree primero el nuevo secreto, luego péguelo en el panel.

Free o Standard

El nivel Free (F0) permite 10 000 mensajes al mes en los canales premium, lo que basta para la mayoría de los despliegues autoalojados. Pase a Standard (S1) si espera volúmenes superiores.

Permisos de Graph

Permiso Lo que aporta Sin él
User.Read.All Los nombres y las fotos de los participantes La integración funciona, las tarjetas no muestran ninguna foto
AppCatalog.Read.All El panel lee el catálogo de aplicaciones de su organización El panel no dice nada del catálogo, y su botón propone publicar o actualizar sin saber cuál de las dos

Ambos son permisos de aplicación, y ambos exigen el consentimiento de administrador. El plugin reclama un token nuevo en cada lectura del catálogo, de modo que un consentimiento concedido con el servidor en marcha se aplica ya en la lectura siguiente, sin reinicio.

La publicación reclama un tercer permiso, el delegado AppCatalog.ReadWrite.All, y funciona de otra manera. No está declarado en el registro de aplicación: el panel de administración lo pide en el momento en que usted intenta publicar.

Instalar el plugin

Copie drovio-teams.jar en la carpeta de paquetes del servidor, luego declárelo en settings.conf:

"plugin_management": {
  "plugins": [
    {
      "classpath": "/opt/drovio-server/packages/drovio-teams.jar",
      "path": "com.drovio.server.teams",
      "ext": "java",
      "base_address": "drovio.server.msteams"
    }
  ]
}

La clave es plugin_management. Escribir plugin_manager da un plugin que no se carga nunca, sin que ningún error lo señale. El base_address vale drovio.server.msteams, dirección que la aplicación Drovio y el servidor emplean ambos en su código.

Reinicie el servidor. Una entrada Microsoft Teams aparece en el panel de administración, y solo aparece cuando el plugin está cargado.

Por qué un reinicio aquí

La mayor parte de la configuración de Drovio Server se aplica en caliente, pero los plugins solo se cargan al arrancar. Cualquier modificación de plugin_management, incluida la de este plugin, no surte efecto hasta el reinicio siguiente.

Configurar la integración

Abra la entrada Microsoft Teams del panel de administración.

Campo De dónde viene
Status Enabled o Disabled
Application ID El client_id anotado en Azure
Client secret El secreto que ha copiado
Tenant ID El tenant_id anotado en Azure
Launch URI Precargado desde la URL del servidor
Join URI Precargado desde la URL del servidor

El guardado inscribe los valores en la configuración del servidor y surte efecto desde la llamada siguiente, sin reinicio. El secreto de cliente ya no se muestra nunca más: dejar el campo vacío conserva el que está almacenado.

Antes de la 3.6.6, cambiar el Application ID exigía un reinicio

Las versiones anteriores lo leían una sola vez al arrancar el servidor. El bot seguía por tanto comprobando las llamadas entrantes contra el valor antiguo y respondía 401 a cada petición, registrando Bot authentication failed: Invalid JWT audience.

Pasar el estado a Disabled detiene el bot y las acciones que vienen de la aplicación Drovio, dejando este panel accesible para configurar la integración.

Referencia de configuración

Estas son las claves del elemento msteams de settings.conf, si prefiere editarlo directamente.

El plugin escribe él mismo este elemento en el primer arranque que no encuentra ninguno, de modo que un servidor puede desplegarse con el plugin y configurarse enteramente desde el panel.

Clave Por defecto Significado
enabled false Activa la integración. En su ausencia, el valor aplicado es false
client_id Application (client) ID del bot
client_secret Secreto de cliente del bot
tenant_id Directory (tenant) ID. Vacío, designa un bot multi-tenant, cuya creación Microsoft ha abandonado desde julio de 2025
launch_uri <url del servidor>/launch La dirección a la que una tarjeta de Teams envía a un usuario para iniciar una llamada
join_uri <url del servidor>/join/app La dirección a la que una tarjeta de Teams envía a un usuario para unirse a una llamada

Construir y publicar la aplicación de Teams

La aplicación es un archivo zip que contiene el manifest y los iconos. La sección App package del panel de administración permite construirla.

Campo Observaciones
Application ID Precargado desde la configuración
Application ID URI Precargado con api://<app id>. Cámbielo solo si Entra ID expone otro
Version Se entrega con el plugin, mostrada a título informativo. Es la actualización del plugin la que publica una nueva versión

Download le da el archivo para depositarlo usted mismo, desde el centro de administración de Teams.

El otro botón le conecta a Microsoft y coloca la aplicación directamente en el catálogo de su organización. Su etiqueta sigue lo que contiene el catálogo: Publish cuando la aplicación no está en él, Update to x.y.z cuando contiene una versión más antigua, y Up to date cuando no hay nada que enviar. Es la lectura de ese estado lo que aporta AppCatalog.Read.All. Sin él, el botón muestra Publish or update y cubre los dos casos, lo que funciona igual de bien.

La publicación exige una cuenta que disponga del rol de administrador de Teams: cualquier otra cuenta solo puede someter la aplicación a revisión, la cual espera después una aprobación en el centro de administración de Teams. Nada de esa conexión se conserva: publicar de nuevo vuelve a conectar.

El catálogo refleja las políticas de gestión de aplicaciones del tenant, que Microsoft aplica en un plazo de 24 a 48 horas tras una publicación. Una aplicación publicada hace un instante puede por tanto no figurar aún en él, y el panel puede seguir proponiendo publicarla.

Autorizar la aplicación y hacerla fácil de encontrar

En el centro de administración de Teams, vaya a Teams apps y luego Manage apps, busque Drovio, y pase su estado a Allowed.

La aplicación muestra la foto de perfil de los participantes. En la pestaña Permissions, haga clic en Review permissions y concédalos.

Para poner la aplicación delante de sus usuarios, vaya a Teams apps y luego Setup policies. Modifique la política Global (Org-wide default), o cree una y asígnela a un grupo. Bajo Pinned apps, añada Drovio y ordénela en el ámbito Messaging extensions.

Lo que hay que saber de las políticas de anclaje

  • La aplicación se abre desde el + del cuadro de redacción. El cliente Teams actual ya no muestra los iconos de extensiones de mensaje junto a esa zona. No hay, por tanto, ningún icono que anclar delante. La política fija el orden dentro del menú +, y es eso lo que coloca a Drovio en cabeza.
  • Un cambio de política tarda unas horas en llegar a los clientes, y una vuelta atrás otro tanto.
  • Dejar User pinning desactivado elimina los anclajes que sus usuarios han hecho ellos mismos.