Skip to content

Commit

Permalink
fix: USGovSingleTenant OAuthEndpoint (#4588)
Browse files Browse the repository at this point in the history
* fix usgov single tenant

* fix js lint
  • Loading branch information
fangyangci authored Dec 21, 2023
1 parent 685bdd2 commit 084ade9
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 32 deletions.
44 changes: 29 additions & 15 deletions libraries/botbuilder/src/botFrameworkAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import {
GovernmentConstants,
JwtTokenValidation,
MicrosoftAppCredentials,
MicrosoftGovernmentAppCredentials,
SignInUrlResponse,
SimpleCredentialProvider,
SkillValidation,
Expand Down Expand Up @@ -254,11 +255,19 @@ export class BotFrameworkAdapter
);
this.credentialsProvider = new SimpleCredentialProvider(this.credentials.appId, '');
} else {
this.credentials = new MicrosoftAppCredentials(
this.settings.appId,
this.settings.appPassword || '',
this.settings.channelAuthTenant
);
if (JwtTokenValidation.isGovernment(this.settings.channelService)) {
this.credentials = new MicrosoftGovernmentAppCredentials(
this.settings.appId,
this.settings.appPassword || '',
this.settings.channelAuthTenant
);
} else {
this.credentials = new MicrosoftAppCredentials(
this.settings.appId,
this.settings.appPassword || '',
this.settings.channelAuthTenant
);
}
this.credentialsProvider = new SimpleCredentialProvider(
this.credentials.appId,
this.settings.appPassword || ''
Expand All @@ -280,10 +289,6 @@ export class BotFrameworkAdapter
ChannelValidation.OpenIdMetadataEndpoint = this.settings.openIdMetadata;
GovernmentChannelValidation.OpenIdMetadataEndpoint = this.settings.openIdMetadata;
}
if (JwtTokenValidation.isGovernment(this.settings.channelService)) {
this.credentials.oAuthEndpoint = GovernmentConstants.ToChannelFromBotLoginUrl;
this.credentials.oAuthScope = GovernmentConstants.ToChannelFromBotOAuthScope;
}

// If a NodeWebSocketFactoryBase was passed in, set it on the BotFrameworkAdapter.
if (this.settings.webSocketFactory) {
Expand Down Expand Up @@ -1627,12 +1632,21 @@ export class BotFrameworkAdapter
this.settings.channelAuthTenant
);
} else {
credentials = new MicrosoftAppCredentials(appId, appPassword, this.settings.channelAuthTenant, oAuthScope);
}

if (JwtTokenValidation.isGovernment(this.settings.channelService)) {
credentials.oAuthEndpoint = GovernmentConstants.ToChannelFromBotLoginUrl;
credentials.oAuthScope = oAuthScope || GovernmentConstants.ToChannelFromBotOAuthScope;
if (JwtTokenValidation.isGovernment(this.settings.channelService)) {
credentials = new MicrosoftGovernmentAppCredentials(
appId,
appPassword,
this.settings.channelAuthTenant,
oAuthScope
);
} else {
credentials = new MicrosoftAppCredentials(
appId,
appPassword,
this.settings.channelAuthTenant,
oAuthScope
);
}
}

return credentials;
Expand Down
6 changes: 2 additions & 4 deletions libraries/botbuilder/src/botFrameworkHttpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import {
AppCredentials,
AuthenticationConstants,
ConversationConstants,
GovernmentConstants,
ICredentialProvider,
JwtTokenValidation,
MicrosoftAppCredentials,
MicrosoftGovernmentAppCredentials,
} from 'botframework-connector';

import { USER_AGENT } from './botFrameworkAdapter';
Expand Down Expand Up @@ -158,9 +158,7 @@ export class BotFrameworkHttpClient implements BotFrameworkClient {
protected async buildCredentials(appId: string, oAuthScope?: string): Promise<AppCredentials> {
const appPassword = await this.credentialProvider.getAppPassword(appId);
if (JwtTokenValidation.isGovernment(this.channelService)) {
const appCredentials = new MicrosoftAppCredentials(appId, appPassword, undefined, oAuthScope);
appCredentials.oAuthEndpoint = GovernmentConstants.ToChannelFromBotLoginUrl;
return appCredentials;
return new MicrosoftGovernmentAppCredentials(appId, appPassword, undefined, oAuthScope);
} else {
return new MicrosoftAppCredentials(appId, appPassword, undefined, oAuthScope);
}
Expand Down
24 changes: 16 additions & 8 deletions libraries/botframework-connector/src/auth/appCredentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,11 @@ export abstract class AppCredentials implements ServiceClientCredentials {
* @param channelAuthTenant Optional. The oauth token tenant.
* @param oAuthScope The scope for the token.
*/
constructor(
appId: string,
channelAuthTenant?: string,
oAuthScope: string = AuthenticationConstants.ToBotFromChannelTokenIssuer
) {
constructor(appId: string, channelAuthTenant?: string, oAuthScope: string = null) {
this.appId = appId;
this.tenant = channelAuthTenant;
this.oAuthEndpoint = AuthenticationConstants.ToChannelFromBotLoginUrlPrefix + this.tenant;
this.oAuthScope = oAuthScope;
this.oAuthEndpoint = this.GetToChannelFromBotLoginUrlPrefix() + this.tenant;
this.oAuthScope = oAuthScope && oAuthScope.length > 0 ? oAuthScope : this.GetToChannelFromBotOAuthScope();
}

/**
Expand All @@ -69,7 +65,7 @@ export abstract class AppCredentials implements ServiceClientCredentials {
* Sets tenant to be used for channel authentication.
*/
private set tenant(value: string) {
this._tenant = value && value.length > 0 ? value : AuthenticationConstants.DefaultChannelAuthTenant;
this._tenant = value && value.length > 0 ? value : this.GetDefaultChannelAuthTenant();
}

/**
Expand Down Expand Up @@ -191,6 +187,18 @@ export abstract class AppCredentials implements ServiceClientCredentials {
}
}

protected GetToChannelFromBotOAuthScope(): string {
return AuthenticationConstants.ToChannelFromBotOAuthScope;
}

protected GetToChannelFromBotLoginUrlPrefix(): string {
return AuthenticationConstants.ToChannelFromBotLoginUrlPrefix;
}

protected GetDefaultChannelAuthTenant(): string {
return AuthenticationConstants.DefaultChannelAuthTenant;
}

protected abstract refreshToken(): Promise<AuthenticatorResult>;

/**
Expand Down
12 changes: 12 additions & 0 deletions libraries/botframework-connector/src/auth/governmentConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,21 @@ export namespace GovernmentConstants {

/**
* TO CHANNEL FROM BOT: Login URL
*
* DEPRECATED: DO NOT USE
*/
export const ToChannelFromBotLoginUrl = 'https://login.microsoftonline.us/MicrosoftServices.onmicrosoft.us';

/**
* TO CHANNEL FROM BOT: Login URL prefix
*/
export const ToChannelFromBotLoginUrlPrefix = 'https://login.microsoftonline.us/';

/**
* TO CHANNEL FROM BOT: Default tenant from which to obtain a token for bot to channel communication
*/
export const DefaultChannelAuthTenant = 'MicrosoftServices.onmicrosoft.us';

/**
* TO CHANNEL FROM BOT: OAuth scope to request
*/
Expand Down
1 change: 1 addition & 0 deletions libraries/botframework-connector/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export * from './managedIdentityAppCredentials';
export * from './managedIdentityAuthenticator';
export * from './managedIdentityServiceClientCredentialsFactory';
export * from './microsoftAppCredentials';
export * from './microsoftGovernmentAppCredentials';
export * from './passwordServiceClientCredentialFactory';
export * from './serviceClientCredentialsFactory';
export * from './skillValidation';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @module botframework-connector
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import { GovernmentConstants } from './governmentConstants';
import { MicrosoftAppCredentials } from './microsoftAppCredentials';

/**
* MicrosoftGovermentAppCredentials auth implementation
*/
export class MicrosoftGovernmentAppCredentials extends MicrosoftAppCredentials {
/**
* Initializes a new instance of the [MicrosoftGovernmentAppCredentials](xref:botframework-connector.MicrosoftGovernmentAppCredentials) class.
*
* @param {string} appId The Microsoft app ID.
* @param {string} appPassword The Microsoft app password.
* @param {string} channelAuthTenant Optional. The oauth token tenant.
* @param {string} oAuthScope Optional. The scope for the token.
*/
constructor(appId: string, public appPassword: string, channelAuthTenant?: string, oAuthScope?: string) {
super(appId, appPassword, channelAuthTenant, oAuthScope);
}

protected GetToChannelFromBotOAuthScope(): string {
return GovernmentConstants.ToChannelFromBotOAuthScope;
}

protected GetToChannelFromBotLoginUrlPrefix(): string {
return GovernmentConstants.ToChannelFromBotLoginUrlPrefix;
}

protected GetDefaultChannelAuthTenant(): string {
return GovernmentConstants.DefaultChannelAuthTenant;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ export class MsalServiceClientCredentialsFactory implements ServiceClientCredent
);
}

if (normalizedEndpoint === GovernmentConstants.ToChannelFromBotLoginUrl.toLowerCase()) {
if (normalizedEndpoint.startsWith(GovernmentConstants.ToChannelFromBotLoginUrlPrefix)) {
return new MsalAppCredentials(
this.clientApplication,
appId,
GovernmentConstants.ToChannelFromBotLoginUrl,
undefined,
audience || GovernmentConstants.ToChannelFromBotOAuthScope
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { ServiceClientCredentials } from '@azure/core-http';
import { AuthenticationConstants } from './authenticationConstants';
import { GovernmentConstants } from './governmentConstants';
import { MicrosoftAppCredentials } from './microsoftAppCredentials';
import { MicrosoftGovernmentAppCredentials } from './microsoftGovernmentAppCredentials';
import { ServiceClientCredentialsFactory } from './serviceClientCredentialsFactory';
import { stringExt } from 'botbuilder-stdlib';

Expand Down Expand Up @@ -111,9 +112,8 @@ export class PasswordServiceClientCredentialFactory implements ServiceClientCred

if (normalizedEndpoint?.startsWith(AuthenticationConstants.ToChannelFromBotLoginUrlPrefix)) {
credentials = new MicrosoftAppCredentials(appId, this.password, this.tenantId, audience);
} else if (normalizedEndpoint === GovernmentConstants.ToChannelFromBotLoginUrl.toLowerCase()) {
credentials = new MicrosoftAppCredentials(appId, this.password, this.tenantId, audience);
credentials.oAuthEndpoint = loginEndpoint;
} else if (normalizedEndpoint?.startsWith(GovernmentConstants.ToChannelFromBotLoginUrlPrefix)) {
credentials = new MicrosoftGovernmentAppCredentials(appId, this.password, this.tenantId, audience);
} else {
credentials = new PrivateCloudAppCredentials(
appId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { MicrosoftAppCredentials, AuthenticationConstants } = require('../..');
const assert = require('assert');

describe('MicrosoftAppCredentialsTestSuite', function () {
describe('MicrosoftAppCredentialsTestCase', function () {
it('AssertOAuthEndpointAndOAuthScope', function () {
const credentials1 = new MicrosoftAppCredentials('appId', 'password', 'tenantId', 'audience');
assert.strictEqual(
AuthenticationConstants.ToChannelFromBotLoginUrlPrefix + 'tenantId',
credentials1.oAuthEndpoint
);
assert.strictEqual('audience', credentials1.oAuthScope);

const credentials2 = new MicrosoftAppCredentials('appId', 'password');
assert.strictEqual(
AuthenticationConstants.ToChannelFromBotLoginUrlPrefix +
AuthenticationConstants.DefaultChannelAuthTenant,
credentials2.oAuthEndpoint
);
assert.strictEqual(AuthenticationConstants.ToChannelFromBotOAuthScope, credentials2.oAuthScope);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const { MicrosoftGovernmentAppCredentials, GovernmentConstants } = require('../..');
const assert = require('assert');

describe('MicrosoftGovernmentAppCredentialsTestSuite', function () {
describe('MicrosoftGovernmentAppCredentialsTestCase', function () {
it('AssertOAuthEndpointAndOAuthScope', function () {
const credentials1 = new MicrosoftGovernmentAppCredentials('appId', 'password', 'tenantId', 'audience');
assert.strictEqual(
GovernmentConstants.ToChannelFromBotLoginUrlPrefix + 'tenantId',
credentials1.oAuthEndpoint
);
assert.strictEqual('audience', credentials1.oAuthScope);

const credentials2 = new MicrosoftGovernmentAppCredentials('appId', 'password');
assert.strictEqual(
GovernmentConstants.ToChannelFromBotLoginUrlPrefix + GovernmentConstants.DefaultChannelAuthTenant,
credentials2.oAuthEndpoint
);
assert.strictEqual(GovernmentConstants.ToChannelFromBotOAuthScope, credentials2.oAuthScope);
});
});
});

0 comments on commit 084ade9

Please sign in to comment.