public async authenticate()

in tools/botskills/src/utils/authenticationUtils.ts [126:300]


    public async authenticate(configuration: IConnectConfiguration, manifest: ISkillManifestV1, logger: ILogger): Promise<boolean> {
        let currentCommand: string[] = [];
        try {
            // configuring bot auth settings
            logger.message('Checking for authentication settings ...');
            if (manifest.authenticationConnections && manifest.authenticationConnections.length > 0) {
                const aadConfig: IAuthenticationConnection | undefined = manifest.authenticationConnections.find(
                    (connection: IAuthenticationConnection): boolean => connection.serviceProviderId === 'Azure Active Directory v2');
                if (aadConfig) {
                    await this.validateAzVersion(logger);
                    logger.message('Configuring Azure AD connection ...');

                    let connectionName: string = aadConfig.id;
                    const newScopes: string[] = aadConfig.scopes.split(',');
                    let scopes: string[] = newScopes.slice(0);

                    // check for existing aad connection
                    const listAuthSettingsCommand: string[] = ['az', 'bot', 'authsetting', 'list'];
                    listAuthSettingsCommand.push(...['-n', configuration.botName]);
                    listAuthSettingsCommand.push(...['-g', configuration.resourceGroup]);
                    listAuthSettingsCommand.push(...['--output', 'json']);

                    logger.command('Checking for existing aad connections', listAuthSettingsCommand.join(' '));
                    currentCommand = listAuthSettingsCommand;

                    const connectionsResult: string = await this.childProcessUtils.tryExecute(listAuthSettingsCommand);
                    const connections: IAzureAuthSetting[] = JSON.parse(connectionsResult);
                    const aadConnection: IAzureAuthSetting | undefined = connections.find(
                        (connection: IAzureAuthSetting): boolean =>
                            connection.properties.serviceProviderDisplayName === 'Azure Active Directory v2');
                    if (aadConnection) {
                        const settingName: string = aadConnection.name.split('/')[1];

                        // Get current aad auth setting
                        const showAuthSettingsCommand: string[] = ['az', 'bot', 'authsetting', 'show'];
                        showAuthSettingsCommand.push(...['-n', configuration.botName]);
                        showAuthSettingsCommand.push(...['-g', configuration.resourceGroup]);
                        showAuthSettingsCommand.push(...['-c', settingName]);
                        showAuthSettingsCommand.push(...['--output', 'json']);

                        logger.command('Getting current aad auth settings', showAuthSettingsCommand.join(' '));
                        currentCommand = showAuthSettingsCommand;

                        const botAuthSettingResult: string = await this.childProcessUtils.tryExecute(showAuthSettingsCommand);
                        const botAuthSetting: IAzureAuthSetting = JSON.parse(botAuthSettingResult);
                        const existingScopes: string[] = botAuthSetting.properties.scopes.split(' ');
                        scopes = scopes.concat(existingScopes);
                        connectionName = settingName;

                        // delete current aad auth connection
                        const deleteAuthSettingCommand: string[] = ['az', 'bot', 'authsetting', 'delete'];
                        deleteAuthSettingCommand.push(...['-n', configuration.botName]);
                        deleteAuthSettingCommand.push(...['-g', configuration.resourceGroup]);
                        deleteAuthSettingCommand.push(...['-c', settingName]);
                        deleteAuthSettingCommand.push(...['--output', 'json']);

                        logger.command('Deleting current bot authentication setting', deleteAuthSettingCommand.join(' '));
                        currentCommand = deleteAuthSettingCommand;

                        await this.childProcessUtils.tryExecute(deleteAuthSettingCommand);
                    }

                    // update appsettings.json
                    logger.message('Updating appsettings.json ...');
                    const appSettings: IAppSetting = JSON.parse(readFileSync(configuration.appSettingsFile, 'UTF8'));

                    // check for and remove existing aad connections
                    if (appSettings.oauthConnections !== undefined) {
                        appSettings.oauthConnections = appSettings.oauthConnections.filter(
                            (connection: IOauthConnection): boolean => connection.provider !== 'Azure Active Directory v2');
                    }

                    // set or add new oauth setting
                    const oauthSetting: IOauthConnection = { name: connectionName, provider: 'Azure Active Directory v2' };
                    if (appSettings.oauthConnections === undefined) {
                        appSettings.oauthConnections = [oauthSetting];
                    } else {
                        appSettings.oauthConnections.push(oauthSetting);
                    }

                    // update appsettings.json
                    writeFileSync(configuration.appSettingsFile, JSON.stringify(appSettings, undefined, 4));

                    // Remove duplicate scopes
                    scopes = [...new Set(scopes)];
                    const scopeManifest: IScopeManifest[] = this.createScopeManifest(scopes, logger);

                    // get the information of the app
                    const azureAppShowCommand: string[] = ['az', 'ad', 'app', 'show'];
                    azureAppShowCommand.push(...['--id', appSettings.microsoftAppId]);
                    azureAppShowCommand.push(...['--output', 'json']);

                    logger.command('Getting the app information', azureAppShowCommand.join(' '));
                    currentCommand = azureAppShowCommand;

                    const azureAppShowResult: string = await this.childProcessUtils.tryExecute(azureAppShowCommand);
                    const azureAppReplyUrls: IAppShowReplyUrl = JSON.parse(azureAppShowResult);

                    // get the Reply Urls from the app
                    const replyUrlsSet: Set<string> = new Set(azureAppReplyUrls.replyUrls);
                    // append the necessary Url if it's not already present
                    replyUrlsSet.add('https://token.botframework.com/.auth/web/redirect');
                    const replyUrls: string[] = [...replyUrlsSet];

                    // Update MSA scopes
                    logger.message('Configuring MSA app scopes ...');
                    const azureAppUpdateCommand: string[] = ['az', 'ad', 'app', 'update'];
                    azureAppUpdateCommand.push(...['--id', appSettings.microsoftAppId]);
                    azureAppUpdateCommand.push(...['--reply-urls', replyUrls.join(' ')]);
                    azureAppUpdateCommand.push(...['--output', 'json']);
                    const scopeManifestText: string = JSON.stringify(scopeManifest)
                        .replace(/\"/g, '\'');
                    azureAppUpdateCommand.push(...['--required-resource-accesses', `"${ scopeManifestText }"`]);

                    logger.command('Updating the app information', azureAppUpdateCommand.join(' '));
                    currentCommand = azureAppUpdateCommand;

                    const errorResult: string = await this.childProcessUtils.tryExecute(azureAppUpdateCommand);
                    //  Catch error: Updates to converged applications are not allowed in this version.
                    if (errorResult) {
                        logger.warning('Could not configure scopes automatically.');
                        // manualScopesRequired = true
                    }

                    logger.message('Updating bot oauth settings ...');
                    const authSettingCommand: string[] = ['az', 'bot', 'authsetting', 'create'];
                    authSettingCommand.push(...['--name', configuration.botName]);
                    authSettingCommand.push(...['--resource-group', configuration.resourceGroup]);
                    authSettingCommand.push(...['--setting-name', connectionName]);
                    authSettingCommand.push(...['--client-id', `"${ appSettings.microsoftAppId }"`]);
                    authSettingCommand.push(...['--client-secret', `"${ appSettings.microsoftAppPassword }"`]);
                    authSettingCommand.push(...['--service', 'Aadv2']);
                    authSettingCommand.push(...['--parameters', `clientId="${ appSettings.microsoftAppId }"`]);
                    authSettingCommand.push(...[`clientSecret="${ appSettings.microsoftAppPassword }"`, 'tenantId=common']);
                    authSettingCommand.push(...['--provider-scope-string', `"${ scopes.join(' ') }"`]);
                    authSettingCommand.push(...['--output', 'json']);

                    logger.command('Creating the updated bot authentication setting', authSettingCommand.join(' '));
                    currentCommand = authSettingCommand;

                    await this.childProcessUtils.tryExecute(authSettingCommand);

                    logger.message('Authentication process finished successfully.');

                } else {
                    throw new Error(`There's no Azure Active Directory v2 authentication connection in your Skills manifest.`);
                }
            } else {
                logger.message(`There are no authentication connections in your Skills manifest.`);
            }

            return true;

        } catch (err) {
            logger.warning(`Could not configure authentication connection automatically.`);
            if (currentCommand.length > 0) {
                logger.warning(
                    `There was an error while executing the following command:${ EOL }\t${ currentCommand.join(' ') + EOL + err.message || err }`
                );
                logger.warning(`You must configure one of the following connection types MANUALLY in the Azure Portal:
        ${ manifest.authenticationConnections.map((authConn: IAuthenticationConnection): string => authConn.serviceProviderId)
        .join(', ') }`);
                logger.warning(`For more information on setting up the authentication configuration manually go to:${ EOL + this.docLink }`);
            } else if (manifest.authenticationConnections && manifest.authenticationConnections.length > 0) {
                logger.warning(`${ err.message || err } You must configure one of the following connection types MANUALLY in the Azure Portal:
        ${ manifest.authenticationConnections.map((authConn: IAuthenticationConnection): string => authConn.serviceProviderId)
        .join(', ') }`);
                logger.warning(`For more information on setting up the authentication configuration manually go to:${ EOL + this.docLink }`);
            } else {
                logger.warning(err.message || err);
            }

            return false;
        }
    }