Aller au contenu

Intégration Microsoft Teams

Une intégration Microsoft Teams peut être ajoutée à votre installation de Drovio Server. Elle permet de démarrer et de rejoindre des sessions Drovio depuis Microsoft Teams, par la zone de rédaction ou par commande du bot. Elle se présente sous la forme d'un fichier JAR que vous ajoutez à Drovio Server puis configurez. Vous devrez créer un Azure Bot et une application dans Microsoft Entra ID.

Déclarer le bot dans Azure

La déclaration du bot peut se faire depuis le portail Azure, l'Azure CLI ou Terraform. Les trois aboutissent au même résultat : une inscription d'application, un secret client, et une ressource Azure Bot dont le canal Teams est activé.

Créer la ressource Azure Bot

Dans le portail Azure, choisissez Create a resource, cherchez Azure Bot, puis Create.

Champ Valeur
Bot handle Un nom unique, par exemple Drovio
Subscription L'abonnement à facturer
Resource group Un nouveau groupe, par exemple Drovio
Pricing tier Free (F0)
Type of app Single Tenant
Creation type Create new Microsoft App ID

Faire pointer le bot vers votre serveur

Ouvrez la ressource, puis Settings et Configuration. Renseignez le Messaging endpoint avec :

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

Point d'accès public

La route /msteams/api/messages doit être joignable en HTTPS depuis les serveurs de Microsoft. Si votre Drovio Server est derrière un pare-feu ou un proxy inverse, veillez à ouvrir ce chemin sur Internet.

Appliquez, puis allez dans Settings et Channels, et ajoutez Microsoft Teams.

Relever les trois valeurs dont le plugin a besoin

Toujours sous Settings et Configuration, cliquez sur Manage Password à côté du Microsoft App ID. Cela ouvre l'inscription d'application dans Microsoft Entra ID.

Dans le volet Overview, relevez :

Valeur dans Azure Utilisée comme
Application (client) ID client_id
Directory (tenant) ID tenant_id

Rendez-vous ensuite dans Certificates & secrets, onglet Client secrets, et cliquez sur New client secret. Copiez aussitôt la colonne Value : elle ne s'affiche qu'une fois, et il faut générer un nouveau secret si vous la manquez. C'est le client_secret.

Exposer l'API et accorder l'accès à Graph

Sous Expose an API, cliquez sur Set à côté de l'Application ID URI, puis sur Save.

Sous API permissions, ajoutez une permission sur Microsoft Graph, choisissez Application permissions, et sélectionnez les deux permissions listées plus bas. Accordez-leur le consentement administrateur.

Déclarer l'URI de redirection

Utile seulement si vous comptez publier l'application depuis le panneau d'administration plutôt que de la déposer vous-même.

Sous Authentication, Add a platform, choisissez Web, et ajoutez l'URI de redirection :

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

Sans elle, la publication échoue sur AADSTS500113: No reply address is registered for the application. Si l'accès à l'administration est restreint par adresse IP sur ce serveur, l'adresse depuis laquelle le navigateur revient doit également être autorisée, faute de quoi le retour est refusé par un 403.

Remplacez <your server> par l'URL publique de votre instance, et choisissez votre propre groupe de ressources et votre région.

Ici l'application précède le bot

Le portail crée l'inscription d'application et le bot dans un seul formulaire. La CLI ne le peut pas : az bot create exige l'identifiant d'application comme argument obligatoire, l'inscription doit donc exister d'abord. Le résultat final est identique.

Fixez d'abord les cinq noms, le reste des commandes pourra ensuite être collé tel quel :

Variable Ce qu'elle nomme
SERVER L'URL publique de votre Drovio Server
APP_NAME Le nom d'affichage de l'inscription d'application
BOT_NAME La ressource bot, qui doit être libre à l'échelle d'Azure
GROUP Le groupe de ressources qui porte le bot
LOCATION La région du groupe de ressources
SERVER=https://<your server>
APP_NAME=Drovio
BOT_NAME=Drovio
GROUP=Drovio
LOCATION=westeurope

Créez l'inscription d'application, son service principal, son Application ID URI et son secret client :

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 ligne az ad sp create correspond à l'étape que le portail vous masque. Elle crée le service principal auquel les permissions sont accordées, et sans lui le consentement administrateur échoue. L'URI d'identification est ce que vise le manifest Teams. Le secret client ne s'affiche qu'une fois, veillez à conserver ce que capture la dernière commande.

Demandez les deux permissions Graph, résolues par leur nom afin qu'aucun identifiant n'ait à être recopié. Le consentement viendra plus tard, à la fin de cet onglet :

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"

Cette commande affiche un message vous invitant à lancer az ad app permission grant : ignorez-le, cette commande concerne les permissions déléguées, alors que ces deux-ci sont des permissions d'application.

Puis la ressource bot elle-même, et son 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"

Accorder le consentement en dernier

Le consentement est la dernière étape, et il doit être vérifié. Microsoft Entra ID a besoin que l'inscription d'application, son service principal et les permissions demandées se soient propagés avant de pouvoir agir dessus. Lancée trop tôt, la commande ne signale aucune erreur et n'accorde rien :

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

La dernière commande doit afficher 2. Si elle affiche 0, attendez une minute et rejouez les deux. Accorder le consentement demande le rôle Privileged Role Administrator ou Global Administrator.

Le portail est le recours fiable

Si le compte reste à 0, ouvrez l'inscription d'application dans Microsoft Entra ID, allez dans API permissions et cliquez sur Grant admin consent for <votre tenant>. La colonne Status affiche alors Granted, et la commande ci-dessus affiche 2.

La même mise en place, pour une infrastructure déjà décrite sous forme de code. Elle réclame le fournisseur azuread en version 3 ou supérieure, où sont apparues les petites ressources d'application composables. Les fichiers ci-dessous forment un seul module racine.

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
}

Trois choses à savoir avant d'appliquer :

  • Le secret client atterrit dans l'état Terraform, qui détient alors un identifiant vers votre tenant et doit être protégé comme tel. Retirez la ressource azuread_application_password et créez le secret à la main si cela n'est pas acceptable là où vous conservez votre état.
  • Les deux ressources azuread_app_role_assignment font ce que réalise Grant admin consent dans le portail. L'identité qui exécute Terraform doit disposer du rôle Privileged Role Administrator ou Global Administrator pour les créer.
  • azurerm_bot_service_azure_bot est la ressource Azure Bot. N'utilisez pas l'ancienne azurerm_bot_channels_registration, qui décrit la génération précédente de déclaration de bot.

Un bot mono-tenant sert votre propre tenant, ce dont un déploiement autohébergé a besoin. La distribution multi-tenant vers les tenants de vos clients est un autre sujet, qui passe par AppSource.

Quelle que soit la méthode retenue, le nom du bot compte entre 4 et 42 caractères et doit être libre à l'échelle d'Azure, si bien que Drovio seul peut être déjà pris. La ressource bot elle-même vit à l'emplacement global, quelle que soit la région de son groupe de ressources.

Le secret client expire

Le même secret authentifie le bot quand il répond dans Teams et le plugin quand il appelle Graph. À son expiration, l'application cesse de répondre et le panneau perd la vue du catalogue, jusqu'à ce qu'un nouveau secret soit saisi dans le panneau d'administration. Sa durée dépend de la façon dont vous l'avez créé :

Méthode Durée
Portail À votre choix, 24 mois au maximum, Microsoft conseillant moins de 12
Azure CLI Un an, modifiable par --years sur az ad app credential reset
Terraform Deux ans, la valeur par défaut appliquée par Microsoft Entra ID quand end_date_relative est omis

Notez la date d'expiration quelque part et prévoyez la rotation : créez le nouveau secret d'abord, puis collez-le dans le panneau.

Free ou Standard

Le niveau Free (F0) autorise 10 000 messages par mois sur les canaux premium, ce qui suffit à la plupart des déploiements autohébergés. Passez en Standard (S1) si vous attendez des volumes supérieurs.

Permissions Graph

Permission Ce qu'elle apporte Sans elle
User.Read.All Les noms et les photos des participants L'intégration fonctionne, les cartes n'affichent pas de photo
AppCatalog.Read.All Le panneau lit le catalogue d'applications de votre organisation Le panneau ne dit rien du catalogue, et son bouton propose de publier ou de mettre à jour sans savoir lequel

Ce sont toutes deux des permissions d'application, et toutes deux demandent le consentement administrateur. Le plugin réclame un jeton neuf à chaque lecture du catalogue, si bien qu'un consentement accordé serveur en marche s'applique dès la lecture suivante, sans redémarrage.

La publication réclame une troisième permission, la déléguée AppCatalog.ReadWrite.All, et elle fonctionne autrement. Elle n'est pas déclarée sur l'inscription d'application : le panneau d'administration la demande au moment où vous tentez de publier.

Installer le plugin

Copiez drovio-teams.jar dans le dossier des paquets du serveur, puis déclarez-le dans 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 clé est plugin_management. Écrire plugin_manager donne un plugin qui ne se charge jamais, sans qu'aucune erreur ne le signale. Le base_address vaut drovio.server.msteams, adresse que l'application Drovio et le serveur emploient tous deux dans leur code.

Redémarrez le serveur. Une entrée Microsoft Teams apparaît dans le panneau d'administration, et n'y apparaît que lorsque le plugin est chargé.

Pourquoi un redémarrage ici

La majeure partie de la configuration de Drovio Server s'applique à chaud, mais les plugins ne sont chargés qu'au démarrage. Toute modification de plugin_management, celle de ce plugin comprise, ne prend effet qu'au redémarrage suivant.

Configurer l'intégration

Ouvrez l'entrée Microsoft Teams du panneau d'administration.

Champ D'où il vient
Status Enabled ou Disabled
Application ID Le client_id relevé dans Azure
Client secret Le secret que vous avez copié
Tenant ID Le tenant_id relevé dans Azure
Launch URI Prérempli depuis l'URL du serveur
Join URI Prérempli depuis l'URL du serveur

L'enregistrement inscrit les valeurs dans la configuration du serveur et prend effet dès l'appel suivant, sans redémarrage. Le secret client ne s'affiche plus jamais : laisser le champ vide conserve celui qui est stocké.

Avant la 3.6.6, changer l'Application ID demandait un redémarrage

Les versions antérieures le lisaient une seule fois au démarrage du serveur. Le bot continuait donc de vérifier les appels entrants contre l'ancienne valeur et répondait 401 à chaque requête, en journalisant Bot authentication failed: Invalid JWT audience.

Passer le statut à Disabled arrête le bot et les actions venant de l'application Drovio, tout en laissant ce panneau accessible pour configurer l'intégration.

Référence de configuration

Voici les clés de l'élément msteams de settings.conf, si vous préférez l'éditer directement.

Le plugin écrit lui-même cet élément au premier démarrage qui n'en trouve aucun, si bien qu'un serveur peut être déployé avec le plugin puis configuré entièrement depuis le panneau.

Clé Défaut Signification
enabled false Active l'intégration. En son absence, la valeur retenue est false
client_id Application (client) ID du bot
client_secret Secret client du bot
tenant_id Directory (tenant) ID. Vide, il désigne un bot multi-tenant, dont la création est abandonnée par Microsoft depuis juillet 2025
launch_uri <url du serveur>/launch L'adresse vers laquelle une carte Teams envoie un utilisateur pour démarrer un appel
join_uri <url du serveur>/join/app L'adresse vers laquelle une carte Teams envoie un utilisateur pour rejoindre un appel

Construire et publier l'application Teams

L'application est une archive zip contenant le manifest et les icônes. La section App package du panneau d'administration permet de la construire.

Champ Remarques
Application ID Prérempli depuis la configuration
Application ID URI Prérempli avec api://<app id>. Ne le changez que si Entra ID en expose un autre
Version Livrée avec le plugin, affichée à titre d'information. C'est la mise à jour du plugin qui publie une nouvelle version

Download vous donne l'archive à déposer vous-même, depuis le centre d'administration Teams.

L'autre bouton vous connecte à Microsoft et place l'application directement dans le catalogue de votre organisation. Son libellé suit ce que contient le catalogue : Publish quand l'application n'y est pas, Update to x.y.z quand il en contient une version plus ancienne, et Up to date quand il n'y a rien à envoyer. C'est la lecture de cet état qu'apporte AppCatalog.Read.All. Sans elle, le bouton affiche Publish or update et couvre les deux cas, ce qui fonctionne tout aussi bien.

La publication exige un compte disposant du rôle d'administrateur Teams : tout autre compte ne peut que soumettre l'application à revue, laquelle attend ensuite une approbation dans le centre d'administration Teams. Rien de cette connexion n'est conservé : publier à nouveau reconnecte.

Le catalogue reflète les politiques de gestion d'applications du tenant, que Microsoft applique sous 24 à 48 heures après une publication. Une application publiée à l'instant peut donc ne pas encore y figurer, et le panneau peut continuer de proposer de la publier.

Autoriser l'application et la rendre facile à trouver

Dans le centre d'administration Teams, allez dans Teams apps puis Manage apps, cherchez Drovio, et passez son statut à Allowed.

L'application affiche la photo de profil des participants. Dans l'onglet Permissions, cliquez sur Review permissions et accordez-les.

Pour mettre l'application devant vos utilisateurs, allez dans Teams apps puis Setup policies. Modifiez la politique Global (Org-wide default), ou créez-en une et affectez-la à un groupe. Sous Pinned apps, ajoutez Drovio et ordonnez-la dans la portée Messaging extensions.

Ce qu'il faut savoir des politiques d'épinglage

  • L'application s'ouvre depuis le + de la zone de rédaction. Le client Teams actuel n'affiche plus les icônes d'extensions de message à côté de cette zone. Il n'y a donc aucune icône à épingler devant. La politique fixe l'ordre à l'intérieur du menu +, et c'est ce qui place Drovio en tête.
  • Un changement de politique met quelques heures à atteindre les clients, et un retour en arrière tout autant.
  • Laisser User pinning désactivé supprime les épinglages que vos utilisateurs ont faits eux-mêmes.