* include Single Tenant apps support * change tenantId variable name * fix unit tests --------- Co-authored-by: JhontSouth <jhonatan.sandoval@southworks.com>
This commit is contained in:
Родитель
012a664107
Коммит
e554dc4231
|
@ -68,6 +68,7 @@ export class EmulatorCommands {
|
|||
openBotViaUrlAction({
|
||||
appId: endpoint.appId,
|
||||
appPassword: endpoint.appPassword,
|
||||
tenantId: endpoint.tenantId,
|
||||
channelService: endpoint.channelService as ChannelService,
|
||||
endpoint: endpoint.endpoint,
|
||||
isFromBotFile: true,
|
||||
|
|
|
@ -110,6 +110,7 @@ export class BotSagas {
|
|||
mode: action.payload.mode,
|
||||
msaAppId: action.payload.appId,
|
||||
msaPassword: action.payload.appPassword,
|
||||
msaTenantId: action.payload.tenantId,
|
||||
};
|
||||
let res: Response = yield call([ConversationService, ConversationService.startConversation], serverUrl, payload);
|
||||
if (!res.ok) {
|
||||
|
@ -135,6 +136,7 @@ export class BotSagas {
|
|||
speechKey: action.payload.speechKey,
|
||||
speechRegion: action.payload.speechRegion,
|
||||
user,
|
||||
msaTenantId: action.payload.tenantId,
|
||||
});
|
||||
|
||||
// add a document to the store so the livechat tab is rendered
|
||||
|
|
|
@ -256,6 +256,7 @@ describe('BotCreationDialog tests', () => {
|
|||
endpoint: '',
|
||||
id: expect.any(String),
|
||||
name: '',
|
||||
tenantId: '',
|
||||
type: 'endpoint',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -98,6 +98,7 @@ export class BotCreationDialog extends React.Component<BotCreationDialogProps, B
|
|||
appId: '',
|
||||
appPassword: '',
|
||||
endpoint: '',
|
||||
tenantId: '',
|
||||
}),
|
||||
isAzureGov: false,
|
||||
secret: '',
|
||||
|
@ -121,7 +122,7 @@ export class BotCreationDialog extends React.Component<BotCreationDialogProps, B
|
|||
<Dialog className={dialogStyles.main} title="New bot configuration" cancel={this.onCancel}>
|
||||
<div className={styles.botCreateForm}>
|
||||
<TextField
|
||||
value={this.state.bot.name}
|
||||
value={bot.name}
|
||||
data-prop="name"
|
||||
onChange={this.onInputChange}
|
||||
label={'Bot name'}
|
||||
|
@ -134,7 +135,7 @@ export class BotCreationDialog extends React.Component<BotCreationDialogProps, B
|
|||
placeholder={endpointPlaceholder}
|
||||
label={'Endpoint URL'}
|
||||
required={true}
|
||||
value={this.state.endpoint.endpoint}
|
||||
value={endpoint.endpoint}
|
||||
name={'create-bot-url'}
|
||||
/>
|
||||
{endpointWarning && <span className={styles.endpointWarning}>{endpointWarning}</span>}
|
||||
|
@ -158,6 +159,13 @@ export class BotCreationDialog extends React.Component<BotCreationDialogProps, B
|
|||
value={endpoint.appPassword}
|
||||
/>
|
||||
</Row>
|
||||
<TextField
|
||||
name="tenantId"
|
||||
label="Tenant ID"
|
||||
onChange={this.onInputChange}
|
||||
placeholder="Optional"
|
||||
value={endpoint.tenantId}
|
||||
/>
|
||||
<Row align={RowAlignment.Bottom}>
|
||||
<Checkbox label="Azure for US Government" checked={isAzureGov} onChange={this.onChannelServiceChange} />
|
||||
<LinkButton
|
||||
|
@ -350,6 +358,7 @@ export class BotCreationDialog extends React.Component<BotCreationDialogProps, B
|
|||
id: this.state.endpoint.id.trim(),
|
||||
appId: this.state.endpoint.appId.trim(),
|
||||
appPassword: this.state.endpoint.appPassword.trim(),
|
||||
tenantId: this.state.endpoint.tenantId.trim(),
|
||||
endpoint: this.state.endpoint.endpoint.trim(),
|
||||
};
|
||||
(endpoint as any).channelService = (this.state.endpoint as any).channelService;
|
||||
|
|
|
@ -227,6 +227,7 @@ describe('The OpenBotDialog', () => {
|
|||
mode: 'livechat',
|
||||
speechKey: 'i-am-a-speech-key',
|
||||
speechRegion: 'westus',
|
||||
tenantId: '',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -254,6 +255,7 @@ describe('The OpenBotDialog', () => {
|
|||
mode: 'livechat',
|
||||
speechKey: '',
|
||||
speechRegion: '',
|
||||
tenantId: '',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -111,10 +111,19 @@ export class OpenBotDialog extends Component<OpenBotDialogProps, OpenBotDialogSt
|
|||
|
||||
constructor(props: OpenBotDialogProps) {
|
||||
super(props);
|
||||
const { appId = '', appPassword = '', botUrl = '', isAzureGov = false, isDebug = false, mode = 'livechat' } = props;
|
||||
const {
|
||||
appId = '',
|
||||
appPassword = '',
|
||||
botUrl = '',
|
||||
isAzureGov = false,
|
||||
isDebug = false,
|
||||
mode = 'livechat',
|
||||
tenantId,
|
||||
} = props;
|
||||
this.state = {
|
||||
appId,
|
||||
appPassword,
|
||||
tenantId,
|
||||
botUrl,
|
||||
isAzureGov,
|
||||
isDebug,
|
||||
|
@ -132,6 +141,7 @@ export class OpenBotDialog extends Component<OpenBotDialogProps, OpenBotDialogSt
|
|||
botUrl,
|
||||
appId,
|
||||
appPassword,
|
||||
tenantId,
|
||||
mode,
|
||||
isDebug,
|
||||
isAzureGov,
|
||||
|
@ -180,6 +190,13 @@ export class OpenBotDialog extends Component<OpenBotDialogProps, OpenBotDialogSt
|
|||
value={appPassword}
|
||||
/>
|
||||
</Row>
|
||||
<TextField
|
||||
name="tenantId"
|
||||
label="Tenant ID"
|
||||
onChange={this.onInputChange}
|
||||
placeholder="Optional"
|
||||
value={tenantId}
|
||||
/>
|
||||
{!isDebug && (
|
||||
<Row className={openBotStyles.multiInputRow}>
|
||||
<TextField
|
||||
|
|
|
@ -50,6 +50,7 @@ const mapDispatchToProps = (dispatch: (action: Action) => void): OpenBotDialogPr
|
|||
const {
|
||||
appId = '',
|
||||
appPassword = '',
|
||||
tenantId = '',
|
||||
botUrl = '',
|
||||
mode = 'livechat-url',
|
||||
isAzureGov,
|
||||
|
@ -63,6 +64,7 @@ const mapDispatchToProps = (dispatch: (action: Action) => void): OpenBotDialogPr
|
|||
openBotViaUrlAction({
|
||||
appId,
|
||||
appPassword,
|
||||
tenantId,
|
||||
endpoint: botUrl,
|
||||
mode,
|
||||
channelService: isAzureGov ? 'azureusgovernment' : 'public',
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
export const authentication = {
|
||||
channelService: 'https://dev.botframework.com/',
|
||||
tokenEndpoint: 'https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token',
|
||||
tokenEndpointSingleTenant: 'https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token',
|
||||
openIdMetadata: 'https://login.microsoftonline.com/botframework.com/v2.0/.well-known/openid-configuration',
|
||||
botTokenAudience: 'https://api.botframework.com',
|
||||
};
|
||||
|
@ -53,6 +54,7 @@ export const v31Authentication = {
|
|||
};
|
||||
|
||||
export const v32Authentication = {
|
||||
tokenIssuerSingleTenant: 'https://sts.windows.net/{tenant-id}/',
|
||||
tokenIssuerV1: 'https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/',
|
||||
tokenIssuerV2: 'https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0',
|
||||
};
|
||||
|
|
|
@ -45,22 +45,22 @@ export function createGetBotEndpointHandler(state: ServerState) {
|
|||
if (request.jwt && request.jwt.appid) {
|
||||
request.botEndpoint = endpoints.getByAppId(request.jwt.appid);
|
||||
} else {
|
||||
const { bot, botUrl, channelServiceType, msaAppId, msaPassword } = req.body;
|
||||
const { bot, botUrl, channelServiceType, msaAppId, msaPassword, options, msaTenantId } = req.body;
|
||||
let endpoint = endpoints.get(botUrl);
|
||||
if (!endpoint) {
|
||||
const channelService =
|
||||
channelServiceType === 'azureusgovernment'
|
||||
? usGovernmentAuthentication.channelService
|
||||
: authentication.channelService;
|
||||
|
||||
// create endpoint
|
||||
endpoint = endpoints.set(
|
||||
bot.id,
|
||||
new BotEndpoint(bot.id, bot.id, botUrl, msaAppId, msaPassword, false, channelService)
|
||||
new BotEndpoint(bot.id, bot.id, botUrl, msaAppId, msaPassword, false, channelService, options, msaTenantId)
|
||||
);
|
||||
} else {
|
||||
endpoint.msaAppId = msaAppId;
|
||||
endpoint.msaPassword = msaPassword;
|
||||
endpoint.tenantId = msaTenantId;
|
||||
}
|
||||
request.botEndpoint = endpoint;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ import { getActivitiesForConversation } from './handlers/getActivitiesForConvers
|
|||
|
||||
export function mountConversationsRoutes(emulatorServer: EmulatorRestServer) {
|
||||
const { server, state } = emulatorServer;
|
||||
const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(emulatorServer.options.fetch);
|
||||
const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(emulatorServer.options.fetch, state);
|
||||
const jsonBodyParser = createJsonBodyParserMiddleware();
|
||||
const fetchConversation = createGetConversationHandler(state);
|
||||
|
||||
|
|
|
@ -41,14 +41,22 @@ import {
|
|||
v32Authentication,
|
||||
} from '../../constants/authEndpoints';
|
||||
import { OpenIdMetadata } from '../../utils/openIdMetadata';
|
||||
import { ConversationAPIPathParameters } from '../channel/conversations/types/conversationAPIPathParameters';
|
||||
import { ServerState } from '../../state/serverState';
|
||||
|
||||
export function createBotFrameworkAuthenticationMiddleware(fetch: any) {
|
||||
export function createBotFrameworkAuthenticationMiddleware(fetch: any, state?: ServerState) {
|
||||
const openIdMetadata = new OpenIdMetadata(fetch, authentication.openIdMetadata);
|
||||
const usGovOpenIdMetadata = new OpenIdMetadata(fetch, usGovernmentAuthentication.openIdMetadata);
|
||||
|
||||
return async (req: Restify.Request, res: Restify.Response) => {
|
||||
const authorization = req.header('Authorization');
|
||||
|
||||
const conversationParameters: ConversationAPIPathParameters = req.params;
|
||||
let conversation;
|
||||
if (conversationParameters?.conversationId && state) {
|
||||
conversation = state.conversations.conversationById(conversationParameters.conversationId);
|
||||
}
|
||||
|
||||
if (!authorization) {
|
||||
return;
|
||||
}
|
||||
|
@ -118,7 +126,9 @@ export function createBotFrameworkAuthenticationMiddleware(fetch: any) {
|
|||
|
||||
let issuer;
|
||||
|
||||
if (decoded.payload.ver === '1.0') {
|
||||
if (conversation?.botEndpoint.tenantId) {
|
||||
issuer = v32Authentication.tokenIssuerSingleTenant.replace('{tenant-id}', conversation?.botEndpoint.tenantId);
|
||||
} else if (decoded.payload.ver === '1.0') {
|
||||
issuer = v32Authentication.tokenIssuerV1;
|
||||
} else if (decoded.payload.ver === '2.0') {
|
||||
issuer = v32Authentication.tokenIssuerV2;
|
||||
|
|
|
@ -48,6 +48,7 @@ export class BotEndpoint {
|
|||
public appId?: string;
|
||||
public appPassword?: string;
|
||||
public speechAuthenticationToken?: SpeechAuthenticationToken;
|
||||
public tenantId?: string;
|
||||
|
||||
constructor(
|
||||
public id?: string,
|
||||
|
@ -57,10 +58,12 @@ export class BotEndpoint {
|
|||
public msaPassword?: string,
|
||||
public use10Tokens?: boolean,
|
||||
public channelService?: string,
|
||||
private _options?: BotEndpointOptions
|
||||
private _options?: BotEndpointOptions,
|
||||
public msaTenantId?: string
|
||||
) {
|
||||
this.appId = msaAppId;
|
||||
this.appPassword = msaPassword;
|
||||
this.tenantId = msaTenantId;
|
||||
}
|
||||
|
||||
private willTokenExpireWithin(millisecondsToExpire: number): boolean {
|
||||
|
@ -126,7 +129,8 @@ export class BotEndpoint {
|
|||
} catch (e) {
|
||||
return {
|
||||
status: e.status,
|
||||
message: "The bot's Microsoft App ID or Microsoft App Password is incorrect.",
|
||||
message:
|
||||
"The bot's Microsoft App ID, Microsoft App Password, or Microsoft Tenant ID (Single Tenant apps) is incorrect.",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -149,11 +153,17 @@ export class BotEndpoint {
|
|||
return this.accessToken;
|
||||
}
|
||||
|
||||
let tokenEndpoint;
|
||||
|
||||
// Refresh access token
|
||||
const tokenEndpoint: string =
|
||||
this.channelService === usGovernmentAuthentication.channelService
|
||||
? usGovernmentAuthentication.tokenEndpoint
|
||||
: authentication.tokenEndpoint;
|
||||
if (this.channelService === usGovernmentAuthentication.channelService) {
|
||||
tokenEndpoint = usGovernmentAuthentication.tokenEndpoint;
|
||||
} else if (this.tenantId) {
|
||||
tokenEndpoint = authentication.tokenEndpointSingleTenant.replace('{tenant-id}', this.tenantId);
|
||||
} else {
|
||||
tokenEndpoint = authentication.tokenEndpoint;
|
||||
}
|
||||
|
||||
const resp = await this._options.fetch(tokenEndpoint, {
|
||||
method: 'POST',
|
||||
body: new URLSearchParams({
|
||||
|
|
|
@ -57,7 +57,8 @@ export class EndpointSet {
|
|||
botEndpoint.channelService,
|
||||
{
|
||||
fetch: this._fetch,
|
||||
}
|
||||
},
|
||||
botEndpoint.tenantId
|
||||
);
|
||||
|
||||
this._endpoints[id] = botEndpointInstance;
|
||||
|
|
|
@ -58,6 +58,7 @@ interface StartConversationPayload {
|
|||
mode: EmulatorMode;
|
||||
msaAppId?: string;
|
||||
msaPassword?: string;
|
||||
msaTenantId?: string;
|
||||
}
|
||||
|
||||
export class ConversationService {
|
||||
|
|
|
@ -36,6 +36,7 @@ export interface BotEndpoint {
|
|||
botUrl: string;
|
||||
msaAppId: string;
|
||||
msaPassword: string;
|
||||
msaTenantId?: string;
|
||||
use10Tokens?: boolean;
|
||||
channelService?: string;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче