From e40cd0f87c6a3e3a8087b32dd229541a4bdf523b Mon Sep 17 00:00:00 2001 From: Rohini-Microsoft Date: Tue, 26 Aug 2025 13:04:33 +0530 Subject: [PATCH 1/3] fixed provision failing issue --- extensions/teams/infra/azure.bicep | 2 +- extensions/teams/infra/botRegistration/azurebot.bicep | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/teams/infra/azure.bicep b/extensions/teams/infra/azure.bicep index 8c706f330..b6a85ff9f 100644 --- a/extensions/teams/infra/azure.bicep +++ b/extensions/teams/infra/azure.bicep @@ -1,4 +1,4 @@ -@maxLength(20) +@maxLength(25) @minLength(4) @description('Used to generate names for all resources in this file') param resourceBaseName string diff --git a/extensions/teams/infra/botRegistration/azurebot.bicep b/extensions/teams/infra/botRegistration/azurebot.bicep index ab67c7a56..24694cfd7 100644 --- a/extensions/teams/infra/botRegistration/azurebot.bicep +++ b/extensions/teams/infra/botRegistration/azurebot.bicep @@ -1,4 +1,4 @@ -@maxLength(20) +@maxLength(25) // Changed from 20 to 25 to match parent template @minLength(4) @description('Used to generate names for all resources in this file') param resourceBaseName string @@ -20,6 +20,8 @@ resource botService 'Microsoft.BotService/botServices@2021-03-01' = { displayName: botDisplayName endpoint: 'https://${botAppDomain}/api/messages' msaAppId: botAadAppClientId + msaAppType: 'SingleTenant' + msaAppTenantId: subscription().tenantId } sku: { name: botServiceSku From e58aa18158ba7611d42c00a340d4466a5367036b Mon Sep 17 00:00:00 2001 From: Rohini-Microsoft Date: Thu, 4 Sep 2025 21:47:29 +0530 Subject: [PATCH 2/3] added single tenant --- extensions/teams/config.ts | 1 + extensions/teams/index.ts | 7 ++- extensions/teams/infra/azure.bicep | 8 ++++ extensions/teams/infra/azure.parameters.json | 3 ++ .../infra/botRegistration/azurebot.bicep | 7 +-- extensions/teams/package.json | 3 +- .../teams/scripts/enable-service-principal.js | 48 +++++++++++++++++++ extensions/teams/teamsapp.yml | 8 ++++ extensions/teams/tsconfig.json | 3 +- 9 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 extensions/teams/scripts/enable-service-principal.js diff --git a/extensions/teams/config.ts b/extensions/teams/config.ts index 6d99139a1..8330fc537 100644 --- a/extensions/teams/config.ts +++ b/extensions/teams/config.ts @@ -2,6 +2,7 @@ const config = { botId: process.env.BOT_ID, botPassword: process.env.BOT_PASSWORD, azureFunctionUrl: process.env.AZURE_FUNCTION_URL, + tenantId: process.env.TEAMS_APP_TENANT_ID, }; export default config; diff --git a/extensions/teams/index.ts b/extensions/teams/index.ts index 555a979b2..bc99753b7 100644 --- a/extensions/teams/index.ts +++ b/extensions/teams/index.ts @@ -14,12 +14,17 @@ import { import { TeamsBot } from "./teamsBot"; import config from "./config"; +// Log app configuration but never log secrets +console.log(`Microsoft App Tenant ID: ${config.tenantId}`); +console.log(`Microsoft App ID: ${config.botId}`); + // Create adapter. // See https://aka.ms/about-bot-adapter to learn more about adapters. const credentialsFactory = new ConfigurationServiceClientCredentialFactory({ MicrosoftAppId: config.botId, MicrosoftAppPassword: config.botPassword, - MicrosoftAppType: "MultiTenant", + MicrosoftAppType: "SingleTenant", + MicrosoftAppTenantId: config.tenantId }); const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication( diff --git a/extensions/teams/infra/azure.bicep b/extensions/teams/infra/azure.bicep index b6a85ff9f..b5b57237f 100644 --- a/extensions/teams/infra/azure.bicep +++ b/extensions/teams/infra/azure.bicep @@ -6,6 +6,9 @@ param resourceBaseName string @description('Required when create Azure Bot service') param botAadAppClientId string +@description('Required when using SingleTenant or UserAssignedMSI app type') +param botAadAppTenantId string + @secure() @description('Required by Bot Framework package in your bot project') param botAadAppClientSecret string @@ -69,6 +72,10 @@ resource webApp 'Microsoft.Web/sites@2021-02-01' = { name: 'AZURE_FUNCTION_URL' value: azureFunctionURL } + { + name: 'TEAMS_APP_TENANT_ID' + value: botAadAppTenantId + } ] ftpsState: 'FtpsOnly' } @@ -81,6 +88,7 @@ module azureBotRegistration './botRegistration/azurebot.bicep' = { params: { resourceBaseName: resourceBaseName botAadAppClientId: botAadAppClientId + botAadAppTenantId: botAadAppTenantId botAppDomain: webApp.properties.defaultHostName botDisplayName: botDisplayName } diff --git a/extensions/teams/infra/azure.parameters.json b/extensions/teams/infra/azure.parameters.json index 2d8bb37da..c342ec592 100644 --- a/extensions/teams/infra/azure.parameters.json +++ b/extensions/teams/infra/azure.parameters.json @@ -8,6 +8,9 @@ "botAadAppClientId": { "value": "${{BOT_ID}}" }, + "botAadAppTenantId": { + "value": "${{TEAMS_APP_TENANT_ID}}" + }, "botAadAppClientSecret": { "value": "${{SECRET_BOT_PASSWORD}}" }, diff --git a/extensions/teams/infra/botRegistration/azurebot.bicep b/extensions/teams/infra/botRegistration/azurebot.bicep index 24694cfd7..2251c96b4 100644 --- a/extensions/teams/infra/botRegistration/azurebot.bicep +++ b/extensions/teams/infra/botRegistration/azurebot.bicep @@ -10,9 +10,10 @@ param botServiceName string = resourceBaseName param botServiceSku string = 'F0' param botAadAppClientId string param botAppDomain string +param botAadAppTenantId string // Register your web service as a bot with the Bot Framework -resource botService 'Microsoft.BotService/botServices@2021-03-01' = { +resource botService 'Microsoft.BotService/botServices@2023-09-15-preview' = { kind: 'azurebot' location: 'global' name: botServiceName @@ -21,7 +22,7 @@ resource botService 'Microsoft.BotService/botServices@2021-03-01' = { endpoint: 'https://${botAppDomain}/api/messages' msaAppId: botAadAppClientId msaAppType: 'SingleTenant' - msaAppTenantId: subscription().tenantId + msaAppTenantId: botAadAppTenantId } sku: { name: botServiceSku @@ -29,7 +30,7 @@ resource botService 'Microsoft.BotService/botServices@2021-03-01' = { } // Connect the bot service to Microsoft Teams -resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = { +resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2023-09-15-preview' = { parent: botService location: 'global' name: 'MsTeamsChannel' diff --git a/extensions/teams/package.json b/extensions/teams/package.json index 72aa6557a..92fc66b2d 100644 --- a/extensions/teams/package.json +++ b/extensions/teams/package.json @@ -16,7 +16,8 @@ "build": "tsc --build", "start": "node ./lib/index.js", "watch": "nodemon --exec \"npm run start\"", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "enable-sp": "node ./scripts/enable-service-principal.js" }, "repository": { "type": "git", diff --git a/extensions/teams/scripts/enable-service-principal.js b/extensions/teams/scripts/enable-service-principal.js new file mode 100644 index 000000000..0a22dc41b --- /dev/null +++ b/extensions/teams/scripts/enable-service-principal.js @@ -0,0 +1,48 @@ +// Script to create a service principal for the Microsoft Entra application +const { exec } = require('child_process'); +const util = require('util'); +const execPromise = util.promisify(exec); + +async function createServicePrincipal() { + const appId = process.env.BOT_ID; + + if (!appId) { + console.error('Error: BOT_ID environment variable is not set'); + process.exit(1); + } + + console.log(`Creating service principal for AAD application with ID: ${appId}`); + + try { + // Check if Azure CLI is installed and logged in + await execPromise('az account show'); + + // Check if service principal already exists + const checkCmd = `az ad sp list --filter "appId eq '${appId}'"`; + const { stdout } = await execPromise(checkCmd); + + const existingSpList = JSON.parse(stdout); + if (existingSpList && existingSpList.length > 0) { + console.log(`Service principal for application ID ${appId} already exists. Skipping creation.`); + process.exit(0); + } + + // Create service principal + const createCmd = `az ad sp create --id "${appId}"`; + await execPromise(createCmd); + + console.log('Service principal created successfully.'); + } catch (error) { + console.error('Error:', error.message); + if (error.message.includes('az: not found') || error.message.includes('not recognized as an internal or external command')) { + console.error('Azure CLI is not installed or not in PATH. Please install it first.'); + } else if (error.message.includes('Please run az login')) { + console.error('You are not logged into Azure. Please run az login first.'); + } else { + console.error('Failed to create service principal. Please ensure you have the right permissions.'); + } + process.exit(1); + } +} + +createServicePrincipal(); diff --git a/extensions/teams/teamsapp.yml b/extensions/teams/teamsapp.yml index 4c7018462..c4000bd75 100644 --- a/extensions/teams/teamsapp.yml +++ b/extensions/teams/teamsapp.yml @@ -27,6 +27,14 @@ provision: botId: BOT_ID # The Microsoft Entra application's client secret created for bot. botPassword: SECRET_BOT_PASSWORD + + # Create service principal for the Microsoft Entra application + - uses: cli/runNpmCommand + name: Enable Service Principal + with: + args: run enable-sp + env: + BOT_ID: ${{BOT_ID}} - uses: arm/deploy # Deploy given ARM templates parallelly. with: diff --git a/extensions/teams/tsconfig.json b/extensions/teams/tsconfig.json index 523f4a057..0d39545cd 100644 --- a/extensions/teams/tsconfig.json +++ b/extensions/teams/tsconfig.json @@ -2,7 +2,8 @@ "compilerOptions": { "declaration": true, "target": "es2021", - "module": "commonjs", + "module": "node16", + "moduleResolution": "node16", "outDir": "./lib", "rootDir": "./", "sourceMap": true, From 992f71d615ea59d2b3aa3e285b50931410a8b905 Mon Sep 17 00:00:00 2001 From: Rohini-Microsoft Date: Fri, 5 Sep 2025 09:50:48 +0530 Subject: [PATCH 3/3] removed console --- extensions/teams/index.ts | 4 ---- extensions/teams/scripts/enable-service-principal.js | 2 -- 2 files changed, 6 deletions(-) diff --git a/extensions/teams/index.ts b/extensions/teams/index.ts index bc99753b7..3eae007b8 100644 --- a/extensions/teams/index.ts +++ b/extensions/teams/index.ts @@ -14,10 +14,6 @@ import { import { TeamsBot } from "./teamsBot"; import config from "./config"; -// Log app configuration but never log secrets -console.log(`Microsoft App Tenant ID: ${config.tenantId}`); -console.log(`Microsoft App ID: ${config.botId}`); - // Create adapter. // See https://aka.ms/about-bot-adapter to learn more about adapters. const credentialsFactory = new ConfigurationServiceClientCredentialFactory({ diff --git a/extensions/teams/scripts/enable-service-principal.js b/extensions/teams/scripts/enable-service-principal.js index 0a22dc41b..303a7509c 100644 --- a/extensions/teams/scripts/enable-service-principal.js +++ b/extensions/teams/scripts/enable-service-principal.js @@ -11,8 +11,6 @@ async function createServicePrincipal() { process.exit(1); } - console.log(`Creating service principal for AAD application with ID: ${appId}`); - try { // Check if Azure CLI is installed and logged in await execPromise('az account show');