Ir para o conteúdo

Integração Microsoft Teams

Uma integração Microsoft Teams pode ser adicionada à sua instalação do Drovio Server. Permite iniciar e entrar em sessões Drovio a partir do Microsoft Teams, pela zona de redação ou por comando do bot. Apresenta-se sob a forma de um ficheiro JAR que adiciona ao Drovio Server e depois configura. Terá de criar um Azure Bot e uma aplicação no Microsoft Entra ID.

Declarar o bot no Azure

A declaração do bot pode fazer-se a partir do portal Azure, do Azure CLI ou do Terraform. Os três conduzem ao mesmo resultado: um registo de aplicação, um segredo de cliente, e um recurso Azure Bot cujo canal Teams está ativado.

Criar o recurso Azure Bot

No portal Azure, escolha Create a resource, procure Azure Bot, depois Create.

Campo Valor
Bot handle Um nome único, por exemplo Drovio
Subscription A subscrição a faturar
Resource group Um novo grupo, por exemplo Drovio
Pricing tier Free (F0)
Type of app Single Tenant
Creation type Create new Microsoft App ID

Fazer o bot apontar para o seu servidor

Abra o recurso, depois Settings e Configuration. Preencha o Messaging endpoint com:

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

Ponto de acesso público

A rota /msteams/api/messages deve ser acessível em HTTPS a partir dos servidores da Microsoft. Se o seu Drovio Server estiver atrás de uma firewall ou de um proxy inverso, tenha o cuidado de abrir este caminho na Internet.

Aplique, depois vá a Settings e Channels, e adicione Microsoft Teams.

Recolher os três valores de que o plugin precisa

Ainda sob Settings e Configuration, clique em Manage Password ao lado do Microsoft App ID. Isso abre o registo de aplicação no Microsoft Entra ID.

No painel Overview, recolha:

Valor no Azure Utilizado como
Application (client) ID client_id
Directory (tenant) ID tenant_id

Vá em seguida a Certificates & secrets, separador Client secrets, e clique em New client secret. Copie logo a coluna Value: só é apresentada uma vez, e é preciso gerar um novo segredo se a perder. É o client_secret.

Expor a API e conceder o acesso ao Graph

Sob Expose an API, clique em Set ao lado do Application ID URI, depois em Save.

Sob API permissions, adicione uma permissão sobre o Microsoft Graph, escolha Application permissions, e selecione as duas permissões listadas mais abaixo. Conceda-lhes o consentimento de administrador.

Declarar o URI de redirecionamento

Útil apenas se contar publicar a aplicação a partir do painel de administração em vez de a depositar você mesmo.

Sob Authentication, Add a platform, escolha Web, e adicione o URI de redirecionamento:

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

Sem ele, a publicação falha com AADSTS500113: No reply address is registered for the application. Se o acesso à administração estiver restringido por endereço IP neste servidor, o endereço a partir do qual o navegador regressa deve igualmente ser autorizado, sem o que o regresso é recusado com um 403.

Substitua <your server> pelo URL público da sua instância, e escolha o seu próprio grupo de recursos e a sua região.

Aqui a aplicação precede o bot

O portal cria o registo de aplicação e o bot num único formulário. O CLI não o pode fazer: az bot create exige o identificador de aplicação como argumento obrigatório, pelo que o registo deve existir primeiro. O resultado final é idêntico.

Fixe primeiro os cinco nomes, podendo o resto dos comandos ser colado tal e qual:

Variável O que designa
SERVER O URL público do seu Drovio Server
APP_NAME O nome de apresentação do registo de aplicação
BOT_NAME O recurso bot, que deve estar livre à escala do Azure
GROUP O grupo de recursos que suporta o bot
LOCATION A região do grupo de recursos
SERVER=https://<your server>
APP_NAME=Drovio
BOT_NAME=Drovio
GROUP=Drovio
LOCATION=westeurope

Crie o registo de aplicação, o seu serviço principal, o seu Application ID URI e o seu segredo 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)

A linha az ad sp create corresponde ao passo que o portal lhe oculta. Cria o serviço principal ao qual as permissões são concedidas, e sem ele o consentimento de administrador falha. O URI de identificação é aquilo que o manifest do Teams visa. O segredo de cliente só é apresentado uma vez, tenha o cuidado de conservar o que o último comando captura.

Peça as duas permissões Graph, resolvidas pelo seu nome para que nenhum identificador tenha de ser copiado. O consentimento virá mais tarde, no fim deste separador:

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 apresenta uma mensagem convidando-o a lançar az ad app permission grant: ignore-a, esse comando diz respeito às permissões delegadas, ao passo que estas duas são permissões de aplicação.

Depois o próprio recurso bot, e o seu canal 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 o consentimento em último lugar

O consentimento é o último passo, e deve ser verificado. O Microsoft Entra ID precisa de que o registo de aplicação, o seu serviço principal e as permissões pedidas se tenham propagado antes de poder agir sobre eles. Lançado demasiado cedo, o comando não assinala qualquer erro e nada concede:

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

O último comando deve apresentar 2. Se apresentar 0, aguarde um minuto e repita os dois. Conceder o consentimento exige o papel Privileged Role Administrator ou Global Administrator.

O portal é o recurso fiável

Se a contagem se mantiver em 0, abra o registo de aplicação no Microsoft Entra ID, vá a API permissions e clique em Grant admin consent for <o seu tenant>. A coluna Status apresenta então Granted, e o comando acima apresenta 2.

A mesma instalação, para uma infraestrutura já descrita sob a forma de código. Exige o fornecedor azuread na versão 3 ou superior, onde surgiram os pequenos recursos de aplicação componíveis. Os ficheiros abaixo formam um único módulo raiz.

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
}

Três coisas a saber antes de aplicar:

  • O segredo de cliente vai parar ao estado do Terraform, que detém então uma credencial para o seu tenant e deve ser protegido como tal. Retire o recurso azuread_application_password e crie o segredo à mão se isso não for aceitável no local onde conserva o seu estado.
  • Os dois recursos azuread_app_role_assignment fazem o que realiza o Grant admin consent no portal. A identidade que executa o Terraform deve dispor do papel Privileged Role Administrator ou Global Administrator para os criar.
  • azurerm_bot_service_azure_bot é o recurso Azure Bot. Não utilize o antigo azurerm_bot_channels_registration, que descreve a geração anterior de declaração de bot.

Um bot monotenant serve o seu próprio tenant, o que é aquilo de que uma implantação autoalojada precisa. A distribuição multitenant para os tenants dos seus clientes é outro assunto, que passa pelo AppSource.

Seja qual for o método escolhido, o nome do bot tem entre 4 e 42 caracteres e deve estar livre à escala do Azure, pelo que Drovio sozinho pode já estar tomado. O próprio recurso bot vive na localização global, seja qual for a região do seu grupo de recursos.

O segredo de cliente expira

O mesmo segredo autentica o bot quando este responde no Teams e o plugin quando este chama o Graph. Na sua expiração, a aplicação deixa de responder e o painel perde a visão do catálogo, até que um novo segredo seja introduzido no painel de administração. A sua duração depende da forma como o criou:

Método Duração
Portal À sua escolha, 24 meses no máximo, aconselhando a Microsoft menos de 12
Azure CLI Um ano, modificável por --years em az ad app credential reset
Terraform Dois anos, o valor predefinido aplicado pelo Microsoft Entra ID quando end_date_relative é omitido

Anote a data de expiração nalgum lado e preveja a rotação: crie primeiro o novo segredo, depois cole-o no painel.

Free ou Standard

O nível Free (F0) autoriza 10 000 mensagens por mês nos canais premium, o que basta para a maioria das implantações autoalojadas. Passe a Standard (S1) se esperar volumes superiores.

Permissões Graph

Permissão O que traz Sem ela
User.Read.All Os nomes e as fotografias dos participantes A integração funciona, os cartões não apresentam fotografia
AppCatalog.Read.All O painel lê o catálogo de aplicações da sua organização O painel nada diz do catálogo, e o seu botão propõe publicar ou atualizar sem saber qual

São ambas permissões de aplicação, e ambas exigem o consentimento de administrador. O plugin pede um token novo a cada leitura do catálogo, pelo que um consentimento concedido com o servidor em funcionamento se aplica logo na leitura seguinte, sem reinício.

A publicação exige uma terceira permissão, a delegada AppCatalog.ReadWrite.All, e funciona de outra forma. Não é declarada no registo de aplicação: o painel de administração pede-a no momento em que tenta publicar.

Instalar o plugin

Copie drovio-teams.jar para a pasta dos pacotes do servidor, depois declare-o em 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"
    }
  ]
}

A chave é plugin_management. Escrever plugin_manager dá um plugin que nunca se carrega, sem que qualquer erro o assinale. O base_address vale drovio.server.msteams, endereço que a aplicação Drovio e o servidor empregam ambos no seu código.

Reinicie o servidor. Uma entrada Microsoft Teams aparece no painel de administração, e só aí aparece quando o plugin está carregado.

Porquê um reinício aqui

A maior parte da configuração do Drovio Server aplica-se a quente, mas os plugins só são carregados no arranque. Qualquer alteração ao plugin_management, incluindo a deste plugin, só produz efeito no reinício seguinte.

Configurar a integração

Abra a entrada Microsoft Teams do painel de administração.

Campo De onde vem
Status Enabled ou Disabled
Application ID O client_id recolhido no Azure
Client secret O segredo que copiou
Tenant ID O tenant_id recolhido no Azure
Launch URI Pré-preenchido a partir do URL do servidor
Join URI Pré-preenchido a partir do URL do servidor

Guardar inscreve os valores na configuração do servidor e produz efeito logo na chamada seguinte, sem reinício. O segredo de cliente nunca mais é apresentado: deixar o campo vazio conserva aquele que está armazenado.

Antes da 3.6.6, mudar o Application ID exigia um reinício

As versões anteriores liam-no uma única vez no arranque do servidor. O bot continuava, portanto, a verificar as chamadas recebidas contra o valor anterior e respondia 401 a cada pedido, registando Bot authentication failed: Invalid JWT audience.

Passar o estado a Disabled interrompe o bot e as ações vindas da aplicação Drovio, deixando este painel acessível para configurar a integração.

Referência de configuração

Eis as chaves do elemento msteams de settings.conf, caso prefira editá-lo diretamente.

O próprio plugin escreve este elemento no primeiro arranque que não encontre nenhum, pelo que um servidor pode ser implantado com o plugin e depois configurado inteiramente a partir do painel.

Chave Predefinição Significado
enabled false Ativa a integração. Na sua ausência, o valor retido é false
client_id Application (client) ID do bot
client_secret Segredo de cliente do bot
tenant_id Directory (tenant) ID. Vazio, designa um bot multitenant, cuja criação foi abandonada pela Microsoft desde julho de 2025
launch_uri <url do servidor>/launch O endereço para o qual um cartão Teams envia um utilizador para iniciar uma chamada
join_uri <url do servidor>/join/app O endereço para o qual um cartão Teams envia um utilizador para entrar numa chamada

Construir e publicar a aplicação Teams

A aplicação é um arquivo zip que contém o manifest e os ícones. A secção App package do painel de administração permite construí-la.

Campo Observações
Application ID Pré-preenchido a partir da configuração
Application ID URI Pré-preenchido com api://<app id>. Só o altere se o Entra ID expuser outro
Version Entregue com o plugin, apresentada a título informativo. É a atualização do plugin que publica uma nova versão

O Download dá-lhe o arquivo para depositar você mesmo, a partir do centro de administração do Teams.

O outro botão liga-o à Microsoft e coloca a aplicação diretamente no catálogo da sua organização. A sua etiqueta segue aquilo que o catálogo contém: Publish quando a aplicação lá não está, Update to x.y.z quando contém uma versão mais antiga, e Up to date quando não há nada a enviar. É a leitura desse estado que o AppCatalog.Read.All traz. Sem ele, o botão apresenta Publish or update e cobre os dois casos, o que funciona igualmente bem.

A publicação exige uma conta com o papel de administrador do Teams: qualquer outra conta só pode submeter a aplicação a revisão, a qual aguarda depois uma aprovação no centro de administração do Teams. Nada dessa ligação é conservado: publicar de novo volta a ligar.

O catálogo reflete as políticas de gestão de aplicações do tenant, que a Microsoft aplica em 24 a 48 horas após uma publicação. Uma aplicação publicada agora mesmo pode, portanto, ainda não lá figurar, e o painel pode continuar a propor publicá-la.

Autorizar a aplicação e torná-la fácil de encontrar

No centro de administração do Teams, vá a Teams apps e depois a Manage apps, procure Drovio, e passe o seu estado a Allowed.

A aplicação apresenta a fotografia de perfil dos participantes. No separador Permissions, clique em Review permissions e conceda-as.

Para colocar a aplicação à frente dos seus utilizadores, vá a Teams apps e depois a Setup policies. Altere a política Global (Org-wide default), ou crie uma e atribua-a a um grupo. Sob Pinned apps, adicione o Drovio e ordene-o no âmbito Messaging extensions.

O que é preciso saber sobre as políticas de afixação

  • A aplicação abre-se a partir do + da zona de redação. O cliente Teams atual já não apresenta os ícones de extensões de mensagem ao lado dessa zona. Não há, portanto, qualquer ícone a afixar à frente. A política fixa a ordem dentro do menu +, e é isso que coloca o Drovio à cabeça.
  • Uma alteração de política demora algumas horas a alcançar os clientes, e um regresso atrás outro tanto.
  • Deixar o User pinning desativado remove as afixações que os seus utilizadores fizeram eles próprios.