Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions extensions/teams/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
3 changes: 2 additions & 1 deletion extensions/teams/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import config from "./config";
const credentialsFactory = new ConfigurationServiceClientCredentialFactory({
MicrosoftAppId: config.botId,
MicrosoftAppPassword: config.botPassword,
MicrosoftAppType: "MultiTenant",
MicrosoftAppType: "SingleTenant",
MicrosoftAppTenantId: config.tenantId
});

const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(
Expand Down
10 changes: 9 additions & 1 deletion extensions/teams/infra/azure.bicep
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
@maxLength(20)
@maxLength(25)
@minLength(4)
@description('Used to generate names for all resources in this file')
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
Expand Down Expand Up @@ -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'
}
Expand All @@ -81,6 +88,7 @@ module azureBotRegistration './botRegistration/azurebot.bicep' = {
params: {
resourceBaseName: resourceBaseName
botAadAppClientId: botAadAppClientId
botAadAppTenantId: botAadAppTenantId
botAppDomain: webApp.properties.defaultHostName
botDisplayName: botDisplayName
}
Expand Down
3 changes: 3 additions & 0 deletions extensions/teams/infra/azure.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"botAadAppClientId": {
"value": "${{BOT_ID}}"
},
"botAadAppTenantId": {
"value": "${{TEAMS_APP_TENANT_ID}}"
},
"botAadAppClientSecret": {
"value": "${{SECRET_BOT_PASSWORD}}"
},
Expand Down
9 changes: 6 additions & 3 deletions extensions/teams/infra/botRegistration/azurebot.bicep
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,24 +10,27 @@ 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
properties: {
displayName: botDisplayName
endpoint: 'https://${botAppDomain}/api/messages'
msaAppId: botAadAppClientId
msaAppType: 'SingleTenant'
msaAppTenantId: botAadAppTenantId
}
sku: {
name: botServiceSku
}
}

// 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'
Expand Down
3 changes: 2 additions & 1 deletion extensions/teams/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
46 changes: 46 additions & 0 deletions extensions/teams/scripts/enable-service-principal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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);
}

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();
8 changes: 8 additions & 0 deletions extensions/teams/teamsapp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion extensions/teams/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"compilerOptions": {
"declaration": true,
"target": "es2021",
"module": "commonjs",
"module": "node16",
"moduleResolution": "node16",
"outDir": "./lib",
"rootDir": "./",
"sourceMap": true,
Expand Down